From c590220caf97b6c77e0f15e77241c3c9a81b58b8 Mon Sep 17 00:00:00 2001 From: spicysharkco <321699413+spicysharkco@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:22:34 +0000 Subject: [PATCH] vmprobe: apply relabelings of the scrape class A VMProbe that references a scrape class got only the authentication settings of the class. The relabelConfigs and metricRelabelConfigs of the class were never added to the scrape config, while VMServiceScrape, VMPodScrape, VMNodeScrape, VMStaticScrape and VMScrapeConfig apply them. Add the class relabelConfigs in front of the relabelings of the targets, and put the class metricRelabelConfigs in front of the ones set on the VMProbe. --- docs/CHANGELOG.md | 1 + .../operator/factory/vmscrapes/probe.go | 8 +++ .../operator/factory/vmscrapes/probe_test.go | 61 +++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 67641c1b22..b4da05bda7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -33,6 +33,7 @@ aliases: * BUGFIX: [helm-converter](https://docs.victoriametrics.com/operator/helm-converter/): convert the `victoria-metrics-alert` chart's legacy values the same way the chart does: `server.remote.read`, `server.remote.write`, `server.notifier.alertmanager`, nested `basicAuth`/`bearer` auth keys and a list-valued `server.notifier.url`. Previously, they were silently dropped, so the generated `VMAlert` lost its remote storage, notifiers and credentials. Plaintext `server.remoteWrite` credentials, legacy or not, are now moved into a generated Secret like the other blocks; before, they were dropped too. The bug has existed since the converter was added in [v0.69.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.69.0). See [#2601](https://github.com/VictoriaMetrics/operator/issues/2601). * BUGFIX: [helm-converter](https://docs.victoriametrics.com/operator/helm-converter/): omit `spec.notifier` for the `victoria-metrics-alert` chart when no notifier URL is set. Previously, the converter generated `spec.notifier: {}`, which the operator webhook rejects, so the output could not be applied. The conversion now fails with an explicit error when the values contain alerting rules but no notifier, since the operator would silently ignore those rules, and when `alertmanager.enabled: true` would make the chart use its bundled Alertmanager, which has no CR equivalent. See [#2601](https://github.com/VictoriaMetrics/operator/issues/2601). * BUGFIX: [helm-converter](https://docs.victoriametrics.com/operator/helm-converter/): convert the charts' `license` and `global.license` blocks into `spec.license` of `VMSingle`, `VMCluster`, `VMAgent`, `VMAlert`, `VMAuth`, `VMAnomaly`, `VLCluster` and `VLAgent` (from both `victoria-logs-agent` and `victoria-logs-collector`). Previously, they were dropped, so the generated CRs started without the enterprise license. The precedence matches the charts: a plaintext key (`license.key`, then `global.license.key`) wins over any Secret reference, which is taken from `license.secret`, `global.license.secret`, `license.keyRef` and `global.license.keyRef`, in that order. See [#2601](https://github.com/VictoriaMetrics/operator/issues/2601). +* BUGFIX: [vmprobe](https://docs.victoriametrics.com/operator/resources/vmprobe/): apply `relabelConfigs` and `metricRelabelConfigs` of the referenced `scrapeClass` to the scrape config of a `VMProbe`, as it is done for the other scrape resources. Previously only the authentication settings of the scrape class were applied. See [#2738](https://github.com/VictoriaMetrics/operator/pull/2738). ## [v0.75.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.75.0) **Release date:** 25 September 2026 diff --git a/internal/controller/operator/factory/vmscrapes/probe.go b/internal/controller/operator/factory/vmscrapes/probe.go index 3ce7597ede..7696062c88 100644 --- a/internal/controller/operator/factory/vmscrapes/probe.go +++ b/internal/controller/operator/factory/vmscrapes/probe.go @@ -3,6 +3,7 @@ package vmscrapes import ( "context" "fmt" + "slices" "gopkg.in/yaml.v2" @@ -65,6 +66,7 @@ func generateProbeConfig( scrapeClass := getScrapeClass(spec.ScrapeClassName, sp) if scrapeClass != nil { mergeEndpointAuthWithScrapeClass(&spec.EndpointAuth, scrapeClass) + spec.MetricRelabelConfigs = slices.Concat(scrapeClass.MetricRelabelConfigs, spec.MetricRelabelConfigs) } // add defaults @@ -89,6 +91,12 @@ func generateProbeConfig( var relabelings []yaml.MapSlice + if scrapeClass != nil { + for _, r := range scrapeClass.RelabelConfigs { + relabelings = append(relabelings, generateRelabelConfig(r)) + } + } + staticTarget := spec.Targets.StaticConfig if spec.Targets.Static != nil { staticTarget = spec.Targets.Static diff --git a/internal/controller/operator/factory/vmscrapes/probe_test.go b/internal/controller/operator/factory/vmscrapes/probe_test.go index 0602172a23..85b1ef2add 100644 --- a/internal/controller/operator/factory/vmscrapes/probe_test.go +++ b/internal/controller/operator/factory/vmscrapes/probe_test.go @@ -705,6 +705,67 @@ relabel_configs: target_label: instance - target_label: __address__ replacement: blackbox:9115 +`, + }) + + // scrapeClass relabelings and metric relabelings + f(opts{ + cr: &vmv1beta1.VMAgent{ + ObjectMeta: metav1.ObjectMeta{Name: "default-vmagent", Namespace: "default"}, + Spec: vmv1beta1.VMAgentSpec{ + CommonScrapeParams: vmv1beta1.CommonScrapeParams{ + ScrapeClasses: []vmv1beta1.ScrapeClass{ + { + Name: "probe-class", + EndpointRelabelings: vmv1beta1.EndpointRelabelings{ + RelabelConfigs: []*vmv1beta1.RelabelConfig{{TargetLabel: "env", Replacement: ptr.To("prod")}}, + MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{{SourceLabels: []string{"__name__"}, Regex: vmv1beta1.StringOrArray{"probe_.*"}, Action: "keep"}}, + }, + }, + }, + }, + }, + }, + sc: &vmv1beta1.VMProbe{ + ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "class-probe"}, + Spec: vmv1beta1.VMProbeSpec{ + ScrapeClassName: ptr.To("probe-class"), + VMProberSpec: vmv1beta1.VMProberSpec{URL: "blackbox:9115"}, + Targets: vmv1beta1.VMProbeTargets{ + Static: &vmv1beta1.VMProbeTargetStatic{ + Targets: []string{"host-1"}, + RelabelConfigs: []*vmv1beta1.RelabelConfig{{TargetLabel: "env", Replacement: ptr.To("user")}}, + }, + }, + MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{{TargetLabel: "probe", Replacement: ptr.To("class-probe")}}, + }, + }, + want: `job_name: probe/default/class-probe +honor_labels: false +metrics_path: /probe +static_configs: +- targets: + - host-1 +relabel_configs: +- target_label: env + replacement: prod +- source_labels: + - __address__ + target_label: __param_target +- target_label: env + replacement: user +- source_labels: + - __param_target + target_label: instance +- target_label: __address__ + replacement: blackbox:9115 +metric_relabel_configs: +- source_labels: + - __name__ + regex: probe_.* + action: keep +- target_label: probe + replacement: class-probe `, }) }