From 5231e6de6e2bdc512f834d0ce9ab04989b9990c1 Mon Sep 17 00:00:00 2001 From: bdchatham Date: Wed, 22 Apr 2026 13:07:51 -0700 Subject: [PATCH] feat(monitoring): stamp EC2-compat labels on generated ServiceMonitor Copies the k8s-scraped `pod` label into legacy EC2 labels `instance_name` and `public_dns` via metricRelabelings, so dashboards filtering on those labels (block size, blocks behind, IAVL/chain-state-growth, etc.) show a unified picture across EC2 and k8s during the migration. This is a temporary shim; removal tracked in #122 for when EC2 scrapes for sei-chain nodes are decommissioned. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../controller/nodedeployment/monitoring.go | 19 +++++-- .../nodedeployment/monitoring_test.go | 50 +++++++++++++++++-- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/internal/controller/nodedeployment/monitoring.go b/internal/controller/nodedeployment/monitoring.go index 9c250be..3d510bc 100644 --- a/internal/controller/nodedeployment/monitoring.go +++ b/internal/controller/nodedeployment/monitoring.go @@ -109,9 +109,22 @@ func endpointSpec(group *seiv1alpha1.SeiNodeDeployment, interval string) map[str "targetLabel": "chain_id", }) } - if len(relabelings) > 0 { - ep["metricRelabelings"] = relabelings - } + // EC2-compat shim: stamp legacy labels from `pod` so dashboards that + // filter on instance_name / public_dns work for both EC2 and k8s scrapes. + // TODO(sei-protocol/sei-k8s-controller#122): remove after EC2 scrape decommission. + relabelings = append(relabelings, + map[string]any{ + "action": "replace", + "sourceLabels": []any{"pod"}, + "targetLabel": "instance_name", + }, + map[string]any{ + "action": "replace", + "sourceLabels": []any{"pod"}, + "targetLabel": "public_dns", + }, + ) + ep["metricRelabelings"] = relabelings return ep } diff --git a/internal/controller/nodedeployment/monitoring_test.go b/internal/controller/nodedeployment/monitoring_test.go index 6b234ed..4b27e15 100644 --- a/internal/controller/nodedeployment/monitoring_test.go +++ b/internal/controller/nodedeployment/monitoring_test.go @@ -122,7 +122,7 @@ func TestGenerateServiceMonitor_ChainIDRelabeling(t *testing.T) { g.Expect(findRelabeling(relabelings, "chain_id")).To(Equal("pacific-1")) } -func TestGenerateServiceMonitor_NoRelabelingsWhenNothingDerivable(t *testing.T) { +func TestGenerateServiceMonitor_OnlyEC2CompatWhenNothingDerivable(t *testing.T) { g := NewWithT(t) group := newTestGroup("role-test", "sei") group.Spec.Monitoring = &seiv1alpha1.MonitoringConfig{ @@ -134,8 +134,26 @@ func TestGenerateServiceMonitor_NoRelabelingsWhenNothingDerivable(t *testing.T) sm := generateServiceMonitor(group) spec := sm.Object["spec"].(map[string]any) ep := spec["endpoints"].([]any)[0].(map[string]any) - _, has := ep["metricRelabelings"] - g.Expect(has).To(BeFalse()) + relabelings := ep["metricRelabelings"].([]any) + g.Expect(findRelabeling(relabelings, "component")).To(Equal("")) + g.Expect(findRelabeling(relabelings, "chain_id")).To(Equal("")) + g.Expect(findSourceRelabeling(relabelings, "instance_name")).To(Equal("pod")) + g.Expect(findSourceRelabeling(relabelings, "public_dns")).To(Equal("pod")) +} + +func TestGenerateServiceMonitor_EC2CompatLabels(t *testing.T) { + g := NewWithT(t) + group := newTestGroup("role-test", "sei") + group.Spec.Monitoring = &seiv1alpha1.MonitoringConfig{ + ServiceMonitor: &seiv1alpha1.ServiceMonitorConfig{}, + } + + sm := generateServiceMonitor(group) + spec := sm.Object["spec"].(map[string]any) + ep := spec["endpoints"].([]any)[0].(map[string]any) + relabelings := ep["metricRelabelings"].([]any) + g.Expect(findSourceRelabeling(relabelings, "instance_name")).To(Equal("pod")) + g.Expect(findSourceRelabeling(relabelings, "public_dns")).To(Equal("pod")) } // findRelabeling returns the `replacement` string for a metricRelabeling @@ -143,9 +161,31 @@ func TestGenerateServiceMonitor_NoRelabelingsWhenNothingDerivable(t *testing.T) func findRelabeling(relabelings []any, targetLabel string) string { for _, r := range relabelings { rule := r.(map[string]any) - if rule["targetLabel"] == targetLabel { - return rule["replacement"].(string) + if rule["targetLabel"] != targetLabel { + continue + } + repl, ok := rule["replacement"].(string) + if !ok { + continue + } + return repl + } + return "" +} + +// findSourceRelabeling returns the first sourceLabels entry for a metricRelabeling +// targeting the given label, or "" if no such rule exists. +func findSourceRelabeling(relabelings []any, targetLabel string) string { + for _, r := range relabelings { + rule := r.(map[string]any) + if rule["targetLabel"] != targetLabel { + continue + } + src, ok := rule["sourceLabels"].([]any) + if !ok || len(src) == 0 { + continue } + return src[0].(string) } return "" }