feat: add service monitors support to prom #66
@ -26,6 +26,7 @@ pub struct KubePrometheusConfig {
|
|||||||
pub prometheus_operator: bool,
|
pub prometheus_operator: bool,
|
||||||
pub alert_receiver_configs: Vec<AlertManagerChannelConfig>,
|
pub alert_receiver_configs: Vec<AlertManagerChannelConfig>,
|
||||||
pub alert_rules: Vec<AlertManagerAdditionalPromRules>,
|
pub alert_rules: Vec<AlertManagerAdditionalPromRules>,
|
||||||
|
pub additional_service_monitors: Vec<ServiceMonitor>,
|
||||||
}
|
}
|
||||||
impl KubePrometheusConfig {
|
impl KubePrometheusConfig {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -49,6 +50,7 @@ impl KubePrometheusConfig {
|
|||||||
kube_scheduler: false,
|
kube_scheduler: false,
|
||||||
alert_receiver_configs: vec![],
|
alert_receiver_configs: vec![],
|
||||||
alert_rules: vec![],
|
alert_rules: vec![],
|
||||||
|
additional_service_monitors: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use crate::modules::{
|
|||||||
helm::chart::HelmChartScore,
|
helm::chart::HelmChartScore,
|
||||||
monitoring::kube_prometheus::types::{
|
monitoring::kube_prometheus::types::{
|
||||||
AlertGroup, AlertManager, AlertManagerAdditionalPromRules, AlertManagerConfig,
|
AlertGroup, AlertManager, AlertManagerAdditionalPromRules, AlertManagerConfig,
|
||||||
AlertManagerRoute, AlertManagerValues,
|
AlertManagerRoute, AlertManagerValues, PrometheusConfig,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,10 +101,23 @@ nodeExporter:
|
|||||||
enabled: {node_exporter}
|
enabled: {node_exporter}
|
||||||
prometheusOperator:
|
prometheusOperator:
|
||||||
enabled: {prometheus_operator}
|
enabled: {prometheus_operator}
|
||||||
prometheus:
|
|
||||||
enabled: {prometheus}
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
let prometheus_config =
|
||||||
|
crate::modules::monitoring::kube_prometheus::types::PrometheusConfigValues {
|
||||||
|
prometheus: PrometheusConfig {
|
||||||
|
prometheus,
|
||||||
|
additional_service_monitors: config.additional_service_monitors.clone(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let prometheus_config_yaml =
|
||||||
|
serde_yaml::to_string(&prometheus_config).expect("Failed to serialize YAML");
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"serialized prometheus config: \n {:#}",
|
||||||
|
prometheus_config_yaml
|
||||||
|
);
|
||||||
|
values.push_str(&prometheus_config_yaml);
|
||||||
|
|
||||||
// add required null receiver for prometheus alert manager
|
// add required null receiver for prometheus alert manager
|
||||||
let mut null_receiver = Mapping::new();
|
let mut null_receiver = Mapping::new();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use harmony_macros::ingress_path;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_yaml::{Mapping, Sequence, Value};
|
use serde_yaml::{Mapping, Sequence, Value};
|
||||||
|
|
||||||
@ -53,3 +54,138 @@ pub struct AlertManagerAdditionalPromRules {
|
|||||||
pub struct AlertGroup {
|
pub struct AlertGroup {
|
||||||
pub groups: Vec<AlertManagerRuleGroup>,
|
pub groups: Vec<AlertManagerRuleGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct PrometheusConfigValues {
|
||||||
|
pub prometheus: PrometheusConfig,
|
||||||
|
}
|
||||||
|
johnride marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct PrometheusConfig {
|
||||||
|
pub prometheus: String,
|
||||||
|
pub additional_service_monitors: Vec<ServiceMonitor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ServiceMonitorTLSConfig {
|
||||||
|
// ## Path to the CA file
|
||||||
|
// ##
|
||||||
|
pub ca_file: String,
|
||||||
|
|
||||||
|
// ## Path to client certificate file
|
||||||
|
// ##
|
||||||
|
pub cert_file: String,
|
||||||
|
|
||||||
|
// ## Skip certificate verification
|
||||||
|
// ##
|
||||||
|
pub insecure_skip_verify: bool,
|
||||||
|
|
||||||
|
// ## Path to client key file
|
||||||
|
// ##
|
||||||
|
pub key_file: String,
|
||||||
|
|
||||||
|
// ## Server name used to verify host name
|
||||||
|
// ##
|
||||||
|
pub server_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ServiceMonitorEndpoint {
|
||||||
|
// ## Name of the endpoint's service port
|
||||||
|
// ## Mutually exclusive with targetPort
|
||||||
|
pub port: String,
|
||||||
|
|
||||||
|
// ## Name or number of the endpoint's target port
|
||||||
|
johnride
commented
This should be a specific type that validates the path This should be a specific type that validates the path
|
|||||||
|
// ## Mutually exclusive with port
|
||||||
|
pub target_port: String,
|
||||||
|
|
||||||
|
// ## File containing bearer token to be used when scraping targets
|
||||||
|
taha marked this conversation as resolved
Outdated
johnride
commented
This should be an enum :
This should be an enum :
```rust
pub enum URLScheme {
HTTP,
HTTPS,
// Maybe others such as :
FILE,
FTP,
OTHER(String), // With this we are both usable with more frequent schemes and extensible
}
impl Display for URLScheme {
// TODO
}
|
|||||||
|
// ##
|
||||||
|
pub bearer_token_file: String,
|
||||||
|
|
||||||
|
// ## Interval at which metrics should be scraped
|
||||||
|
// ##
|
||||||
|
pub interval: String,
|
||||||
|
|
||||||
|
// ## HTTP path to scrape for metrics
|
||||||
|
// ##
|
||||||
|
pub path: String,
|
||||||
|
|
||||||
|
// ## HTTP scheme to use for scraping
|
||||||
|
// ##
|
||||||
|
pub scheme: String,
|
||||||
|
|
||||||
|
// ## TLS configuration to use when scraping the endpoint
|
||||||
|
// ##
|
||||||
|
pub tls_config: ServiceMonitorTLSConfig,
|
||||||
|
|
||||||
|
// ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
|
||||||
|
// ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig
|
||||||
|
// ##
|
||||||
|
// # - action: keep
|
||||||
|
// # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
|
||||||
|
// # sourceLabels: [__name__]
|
||||||
|
pub metric_relabelings: Vec<Mapping>,
|
||||||
|
|
||||||
|
// ## RelabelConfigs to apply to samples before scraping
|
||||||
|
// ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig
|
||||||
|
// ##
|
||||||
|
taha marked this conversation as resolved
Outdated
johnride
commented
I guess operator is not any string? Probably should be an enum too. I guess operator is not any string? Probably should be an enum too.
|
|||||||
|
// # - sourceLabels: [__meta_kubernetes_pod_node_name]
|
||||||
|
// # separator: ;
|
||||||
|
// # regex: ^(.*)$
|
||||||
|
// # targetLabel: nodename
|
||||||
|
// # replacement: $1
|
||||||
|
// # action: replace
|
||||||
|
pub relabelings: Vec<Mapping>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ServiceMonitor {
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
// # Additional labels to set used for the ServiceMonitorSelector. Together with standard labels from the chart
|
||||||
|
pub additional_labels: Mapping,
|
||||||
|
|
||||||
|
// # Service label for use in assembling a job name of the form <label value>-<port>
|
||||||
|
// # If no label is specified, the service name is used.
|
||||||
|
pub job_label: String,
|
||||||
|
|
||||||
|
// # labels to transfer from the kubernetes service to the target
|
||||||
|
johnride
commented
I think we already do have a Label type somewhere. I think it would be more appropriate here than String. That's true for all the label related fields in this file. This Label type might not be fully compatible in its current form/place but it is definitely a semantic that we will see very often in various use cases and implementations. I think it is worth for us to maintain a Label type which we can eventually provide very interesting functionnality for such as search, tracking, matching, versionning, etc. I think we already do have a Label type somewhere. I think it would be more appropriate here than String. That's true for all the label related fields in this file.
This Label type might not be fully compatible in its current form/place but it is definitely a semantic that we will see very often in various use cases and implementations. I think it is worth for us to maintain a Label type which we can eventually provide very interesting functionnality for such as search, tracking, matching, versionning, etc.
|
|||||||
|
pub target_labels: Vec<String>,
|
||||||
|
|
||||||
|
// # labels to transfer from the kubernetes pods to the target
|
||||||
|
pub pod_target_labels: Vec<String>,
|
||||||
|
|
||||||
|
// # Label selector for services to which this ServiceMonitor applies
|
||||||
|
// # Example which selects all services to be monitored
|
||||||
|
// # with label "monitoredby" with values any of "example-service-1" or "example-service-2"
|
||||||
|
// matchExpressions:
|
||||||
|
// - key: "monitoredby"
|
||||||
|
// operator: In
|
||||||
|
// values:
|
||||||
|
// - example-service-1
|
||||||
|
// - example-service-2
|
||||||
|
pub selector: Mapping,
|
||||||
|
|
||||||
|
// # label selector for services
|
||||||
|
pub match_labels: Mapping,
|
||||||
|
|
||||||
|
// # Namespaces from which services are selected
|
||||||
|
// # Match any namespace
|
||||||
|
// any: bool,
|
||||||
|
// # Explicit list of namespace names to select
|
||||||
|
// matchNames: Vec,
|
||||||
|
pub namespace_selector: Mapping,
|
||||||
|
|
||||||
|
// # Endpoints of the selected service to be monitored
|
||||||
|
pub endpoints: Vec<ServiceMonitorEndpoint>,
|
||||||
|
|
||||||
|
// # Fallback scrape protocol used by Prometheus for scraping metrics
|
||||||
|
// # ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#monitoring.coreos.com/v1.ScrapeProtocol
|
||||||
|
pub fallback_scrape_protocol: String,
|
||||||
|
}
|
||||||
|
|||||||
@ -133,6 +133,26 @@ pub fn ingress_path(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify that a string is a valid http scheme
|
||||||
|
/// Panics if not http or https
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn http_scheme(input: TokenStream) -> TokenStream {
|
||||||
|
taha marked this conversation as resolved
Outdated
johnride
commented
What's the use case for this? I don't see this used in this pr. What's the use case for this? I don't see this used in this pr.
taha
commented
For the For the `httpScheme` field, in endpoints. I hadn't yet pushed the commit that uses it
johnride
commented
Yeah ok, I see what you did there. But this is not a good use case for Macros. Macros are a last resort when the type semantics are already correct and we can't rely on the regular rust type system anymore to provide a good UX/DX. In this case a macro outputting a String type prevents us from adding useful functionnality around the "Scheme" idea. I can very well see us eventually detecting the scheme here and performing automatic endpoint discovery and health checks or something like that, which we cannot do if we keep this as a Yeah ok, I see what you did there.
But this is not a good use case for Macros. Macros are a last resort when the type semantics are already correct and we can't rely on the regular rust type system anymore to provide a good UX/DX. In this case a macro outputting a String type prevents us from adding useful functionnality around the "Scheme" idea.
I can very well see us eventually detecting the scheme here and performing automatic endpoint discovery and health checks or something like that, which we cannot do if we keep this as a `String`. See my commnent above, this should be an enum.
|
|||||||
|
let input = parse_macro_input!(input as LitStr);
|
||||||
|
let scheme_str = input.value();
|
||||||
|
|
||||||
|
if scheme_str.to_lowercase() == "http" {
|
||||||
|
let expanded = quote! {(#scheme_str.to_lowercase().to_string()) };
|
||||||
|
return TokenStream::from(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if scheme_str.to_lowercase() == "https" {
|
||||||
|
let expanded = quote! {(#scheme_str.to_lowercase().to_string()) };
|
||||||
|
return TokenStream::from(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Invalid HTTP scheme")
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn cidrv4(input: TokenStream) -> TokenStream {
|
pub fn cidrv4(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as LitStr);
|
let input = parse_macro_input!(input as LitStr);
|
||||||
|
|||||||
Not a String, should be a path type of some sort. I think we already handle this somewhere else correctly.
You might have to implement Serialize for it or wrap it into another type that Serializes as a String but that's ok.