[amazon-cloudwatch-agent-operator] Route SM/PM by cloudwatch.aws/scraper annotation#399
Open
wenegiemepraise wants to merge 8 commits into
Open
[amazon-cloudwatch-agent-operator] Route SM/PM by cloudwatch.aws/scraper annotation#399wenegiemepraise wants to merge 8 commits into
wenegiemepraise wants to merge 8 commits into
Conversation
…er startup The target-allocator declared the enable-prometheus-cr-watcher flag name as a constant but never registered it on the flag set, while the operator passes --enable-prometheus-cr-watcher whenever PrometheusCR.enabled is true. Because args are parsed with pflag.ExitOnError, the unregistered flag caused the binary to print 'unknown flag' and exit(2), putting the target-allocator pod into CrashLoopBackOff. This change registers the flag and ORs it with the YAML prometheus_cr.enabled setting, then fixes three latent defects that were previously unreachable because the binary crashed first: - promOperator: set a non-empty Namespace on the synthetic Prometheus object so the prometheus-operator config generator no longer panics with 'namespace can't be empty' in store.ForNamespace. - promOperator: set EvaluationInterval so the generated config does not render an empty global.evaluation_interval, which the prometheus config parser rejects with 'empty duration string'. - main: create and register service-discovery metrics and pass them to discovery.NewManager; passing a nil sdMetrics map makes every SD provider fail to register, yielding zero discovered targets. RELEASE_NOTES updated.
Add a regression test asserting that loading a Target Allocator config whose static scrape job omits scrape_protocols still yields a non-empty ScrapeProtocols on every loaded scrape config. This is defaulted by the pinned Prometheus library during yaml.UnmarshalStrict into the prometheus Config type, so the distributed /scrape_configs payload is never empty and the agent's prometheus-receiver validation passes. The test fails fast if a future dependency or load-path change drops this defaulting.
The pod-template restart-trigger sha256 was computed from Spec.Config only, so a change to Spec.Prometheus (rendered into a separate ConfigMap) left the pod template byte-identical and the workload controller did not roll the pods. Fold the serialized Spec.Prometheus (PrometheusConfig.Yaml()) into the hash input when it is non-empty, so a Prometheus-only change bumps the pod-template annotation and triggers a rolling restart, matching agent-config behavior. When no Prometheus config is set the hash input is byte-identical to the agent config alone, leaving non-Prometheus agents unaffected.
Add a per-node allocation strategy so each CloudWatch agent (DaemonSet, one per node) scrapes only the ServiceMonitor/PodMonitor targets on its own node, eliminating cross-node/cross-AZ scrape traffic. Targets that cannot be matched to a node-local agent (node-less endpoints, nodes without a Ready agent) fall back to consistent-hashing so they are never silently dropped. - allocation/per_node.go: perNodeAllocator (node index, consistent-hashing fallback ring, unassigned tracking, descriptive logging) + registration. - allocation/strategy.go: Collector.NodeName, NewCollector(name, node), WithFallbackStrategy option, targets_unassigned gauge. - collector/collector.go: capture pod.Spec.NodeName, skip empty-NodeName pods, handle watch.Modified so a collector's node is picked up once scheduled (fixes targets being stuck on the fallback after a DaemonSet rollout). - target/target.go: GetNodeName() from __meta_kubernetes_*_node_name labels. - config + main: FallbackAllocationStrategy wiring. - apis/v1alpha1 + CRD: allocationStrategy enum gains "per-node". - internal/manifests/targetallocator/configmap.go: emit per-node strategy and the consistent-hashing fallback from the CR.
# Conflicts: # cmd/amazon-cloudwatch-agent-target-allocator/main.go
Route ServiceMonitor/PodMonitor discovery across CloudWatch agents by the cloudwatch.aws/scraper annotation on the monitor CR. A monitor annotated cloudwatch.aws/scraper: cluster-scraper is scraped only by the cluster-scraper agent's Target Allocator; all others only by the per-node agent's. Add a scraperRole field to the Target Allocator prometheusCR config (spec.targetAllocator.prometheusCR.scraperRole) and a client-side annotation filter in the TA watcher (annotationRoleMatches) applied during monitor discovery. The cluster-scraper role keeps only annotated monitors; the default (empty) role keeps only unannotated ones, so the two roles partition monitors with no overlap and no gap.
Add a LoadConfig-level test proving the scraper annotation filter is applied during monitor discovery (cluster-scraper and default roles keep/skip the right monitors), and a ConfigMap test asserting scraper_role is emitted when set on the prometheusCR.
Refactor the annotation filter into PrometheusCRWatcher.selectsMonitor and log each ServiceMonitor/PodMonitor the cluster-scraper agent claims via the cloudwatch.aws/scraper annotation (the override event). Add unit tests bringing the routing logic to 100% statement coverage: annotationRoleMatches and selectsMonitor (incl. asserting the override log fires only for the cluster-scraper role), a LoadConfig-level routing test, and a configmap scraper_role assertion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Route ServiceMonitor/PodMonitor discovery across CloudWatch agents by the
cloudwatch.aws/scraperannotation on the monitor CR. A monitor annotatedcloudwatch.aws/scraper: cluster-scraperis scraped only by the cluster-scraper agent's TargetAllocator; all others only by the per-node agent's.
What
spec.targetAllocator.prometheusCR.scraperRolefield (Target Allocator configscraper_role).annotationRoleMatches) applied during monitordiscovery in
LoadConfig.cluster-scraperrole keeps only annotated monitors; the empty(default) role keeps only unannotated ones — complementary, so every monitor is owned by exactly
one agent (no double-scrape, no gap).
Why annotation (not label)
The routing key is behavioural config, not identity. Both agents' TAs already list all monitors
into their cache and filter client-side, and the two roles' selections union to the full set — so
server-side label filtering would gain nothing here. Filtering by annotation is a few lines in the
existing
ListAllcallback.Testing
go build ./...and unit tests pass, incl. newTestAnnotationRoleMatches(8 cases + partition invariant).cluster-scraper TA
/jobs; an unannotated one only in the per-node TA/jobs.GOPROXY=direct GOSUMDB=off(offline proxy); CI is the authoritative gate.Dependencies / stacking
Stacks on the per-node allocation operator work (#398,
ta-per-node-allocation). Companion helm PR:[amazon-cloudwatch-observability] Route SM/PM to cluster-scraper by annotation.