feat(exporter): ability to expose k8s labels as prometheus metrics labels

This commit is contained in:
David Donchez
2026-02-25 10:46:42 +01:00
committed by Paul Laffitte
parent 8274f0bbd7
commit cee171c4e4
5 changed files with 37 additions and 7 deletions
+2
View File
@@ -120,6 +120,8 @@ Usage: x509-certificate-exporter [-hv] [-b value] [--debug] [-d value] [--exclud
--expose-relative-metrics
expose additionnal metrics with relative durations instead
of absolute timestamps
--expose-secret-label=value
expose selected label from kube secrets as prometheus label
-f, --watch-file=value
watch one or more x509 certificate file
-h, --help show this help message and exit
+4
View File
@@ -81,6 +81,9 @@ func main() {
kubeExcludeLabels := stringArrayFlag{}
getopt.FlagLong(&kubeExcludeLabels, "exclude-label", 0, "removes the kube secrets with the given label (or label value if specified) from the watch list (applied after --include-label)")
kubeSecretLabels := stringArrayFlag{}
getopt.FlagLong(&kubeSecretLabels, "expose-secret-label", 0, "expose selected label from kube secrets as prometheus label")
getopt.Parse()
if *help {
@@ -153,6 +156,7 @@ func main() {
KubeExcludeNamespaceLabels: kubeExcludeNamespaceLabels,
KubeIncludeLabels: kubeIncludeLabels,
KubeExcludeLabels: kubeExcludeLabels,
KubeSecretLabels: kubeSecretLabels,
}
if getopt.Lookup("expose-labels").Seen() {
+8 -7
View File
@@ -62,13 +62,14 @@ var DefaultYamlPaths = []YAMLCertRef{
}
type certificateRef struct {
path string
format certificateFormat
certificates []*parsedCertificate
yamlPaths []YAMLCertRef
kubeSecret v1.Secret
kubeConfigMap v1.ConfigMap
kubeSecretKey string
path string
format certificateFormat
certificates []*parsedCertificate
yamlPaths []YAMLCertRef
kubeSecret v1.Secret
kubeConfigMap v1.ConfigMap
kubeSecretKey string
kubeSecretLabels map[string]string
}
type parsedCertificate struct {
+15
View File
@@ -48,6 +48,7 @@ type Exporter struct {
KubeExcludeNamespaceLabels []string
KubeIncludeLabels []string
KubeExcludeLabels []string
KubeSecretLabels []string
kubeClient kubernetes.Interface
listener net.Listener
@@ -395,6 +396,16 @@ func (exporter *Exporter) compareCertificates(
if leftCert.userID != rightCert.userID {
return false
}
if leftRef.format == certificateFormatKubeSecret {
if len(leftRef.kubeSecretLabels) != len(rightRef.kubeSecretLabels) {
return false
}
for key, leftValue := range leftRef.kubeSecretLabels {
if rightValue, exists := rightRef.kubeSecretLabels[key]; !exists || leftValue != rightValue {
return false
}
}
}
return true
}
@@ -473,6 +484,10 @@ func (exporter *Exporter) getBaseLabels(ref *certificateRef) map[string]string {
labels["secret_name"] = filepath.Base(ref.path)
labels["secret_namespace"] = strings.Split(ref.path, "/")[1]
labels["secret_key"] = ref.kubeSecretKey
for key, value := range ref.kubeSecretLabels {
sanitizedKey := regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(key, "_")
labels["secret_label_"+sanitizedKey] = value
}
}
return labels
+8
View File
@@ -47,11 +47,18 @@ func (exporter *Exporter) parseAllKubeObjects() ([]*certificateRef, []error) {
readCertificatesFromSecrets := func(secrets []v1.Secret) (outputs []*certificateRef) {
for _, secret := range secrets {
for key := range MatchingSecretKeys(exporter.KubeSecretTypes, &secret) {
filteredLabels := make(map[string]string)
for _, labelKey := range exporter.KubeSecretLabels {
if value, exists := secret.Labels[labelKey]; exists {
filteredLabels[labelKey] = value
}
}
output = append(output, &certificateRef{
path: fmt.Sprintf("k8s/%s/%s", secret.GetNamespace(), secret.GetName()),
format: certificateFormatKubeSecret,
kubeSecret: secret,
kubeSecretKey: key,
kubeSecretLabels: filteredLabels,
})
}
}
@@ -265,6 +272,7 @@ func (exporter *Exporter) shrinkSecret(secret v1.Secret) v1.Secret {
ObjectMeta: metav1.ObjectMeta{
Name: secret.Name,
Namespace: secret.Namespace,
Labels: secret.Labels,
},
}
for key := range MatchingSecretKeys(exporter.KubeSecretTypes, &secret) {