Conversation
Add the 'elbv2.services.k8s.aws/target-management: ignore' annotation that tells the controller to leave targets alone — no DescribeTargetHealth, no RegisterTargets, no DeregisterTargets. This allows an external controller to own target registration while ACK still manages the target group itself (health checks, attributes, etc.). Three guard points: - sdkFind: skip describeTargets so externally-registered targets are never read from AWS (no drift detected) - sdkUpdate: guard the register/deregister block with the annotation check - sdkCreate: skip the post-create requeue for target registration Templates updated so future code regeneration preserves the behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…for listeners Add the 'elbv2.services.k8s.aws/weight-management: ignore' annotation that tells the controller to not reconcile forward action target group weights. This allows external blue/green deployment tools to manage traffic shifting independently while ACK still manages the rest of the listener configuration. Uses a delta_pre_compare hook (customPreCompare) that copies AWS-side weights into the desired spec before DeepEqual comparison, so weight differences never generate deltas. Since the desired spec is mutated with the latest weights, any ModifyListener calls triggered by other field changes also preserve the AWS-side weights. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: mfanjie The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @mfanjie. Thanks for your PR. I'm waiting for a aws-controllers-k8s member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
- Add nil guard for action pointer in mergeLatestWeights (both listener and rule) since Actions/DefaultActions is []*Action, individual elements can be nil - Add weight-management annotation support to rule resources (isWeightManagementIgnored + mergeLatestWeights + customPreCompare hook) - Add tests for rule weight-management: annotation check, weight merge, and delta suppression with annotation - Fix: use string literal for annotation key in rule package to avoid duplicating listener's exported AnnotationWeightManagement constant Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
/ok-to-test |
| // action weights for target groups. When set to "ignore", the controller | ||
| // will not reconcile weight differences — allowing an external controller | ||
| // or deployment tool to manage blue/green traffic shifting independently. | ||
| AnnotationWeightManagement = "elbv2.services.k8s.aws/weight-management" |
There was a problem hiding this comment.
Feels like this is a use case off ignore-deltas for specific fields? cc @michaelhtm @knottnt - if yes, i think we need a generic solution for all controllers
|
/retest |
…ecksum The generator.yaml was modified but the metadata file wasn't regenerated, causing the CI verify-code-gen check to fail on file_checksum mismatch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@a-hilaly @sapphirew can you please check if it is possible to merge this pr before we have the generic solution being defined, we really need the feature before we use ack in our production env |
|
@mfanjie We've seen a few similar feature requests for other controllers. Given this the ACK team is currently looking into adding a feature for read-only/ignored fields similar to what is discussed in this aws-controllers-k8s/community#2367. The ACK team is hoping that this will allow us to provide a general solution across all of our controllers and avoid adding adhoc custom behavior to individual controllers. |
|
Hi @mfanjie, thanks for the ping and for your patience. Quick update: the generic feature @knottnt mentioned is now in flight. It's an opt-in
How it maps to your two scenarios: Scenario 2 (blue/green weights) — covered by Scenario 1 (externally-registered targets) — this one is better solved by remodeling rather than by an ignore annotation. So the generic feature addresses your weight case at a coarse grain now, and the target case is best handled by the sub-resource approach rather than being folded into the annotation. Since the generic feature is still pre-release and doesn't fully subsume this PR in v1, I'd defer the merge decision to the maintainers. If you need the fine-grained weight behavior and the target opt-out in production now, this controller-specific PR may still be the right near-term path; we'll keep the long-term direction (sub-field ignore + the |
|
Hi @michaelhtm (#85), Wanted to check in on the path forward for this PR. For context, I'm the AWS SA working with the team that submitted this — they're actively migrating ELBv2 infrastructure to ACK and hitting both scenarios (target deregistration + weight reset) in production today. I see the generic ignore-field-drift feature is progressing (runtime#256 + code-generator#714) — that's great. However, looking at the coverage: Scenario 2 (weights): covered by ignore-field-drift ✅ Happy to discuss — just want to make sure we have a clear path so the customer isn't blocked longer than necessary. What would you need to feel comfortable with an approve here? |
|
Hi @knottnt @michaelhtm @mfanjie — following up on this.
The TargetGroupAttachment CRD (long-term direction) doesn't have a timeline yet, and the customer is actively blocked in production today. Request: Could we proceed with merging the target-management annotation portion of this PR as an interim solution for Scenario 1? The weight-management portion can be dropped in favor of the generic Happy to help the contributor (@mfanjie) split the PR if that makes review easier. This is the customer's highest priority request. |
@blackdog0403 The proposed That said we can take a look at splitting out the |
| @@ -1,4 +1,4 @@ | |||
| if delta.DifferentAt("Spec.Targets") { | |||
| if delta.DifferentAt("Spec.Targets") && !isTargetManagementIgnored(desired) { | |||
There was a problem hiding this comment.
Q: Any reason to not filter the Spec.Targets from the Delta entirely? If it is the only field that has drifted there no need to enter sdkUpdate at all.
There was a problem hiding this comment.
@knottnt @mfanjie This is comment from the customer. - "It's better not reading the endpoint back as we want to match the spec, but it's should be fine for now even it it exposed. can we release what we have now?"
Please progress with existing PR #256 and split out target-management annotation to separate PR.
Add end-to-end coverage for the services.k8s.aws/ignore-field-drift annotation (aws-controllers-k8s/runtime#256) on an ELBv2 Listener's forward-action target-group weights, mirroring "Scenario 2" of aws-controllers-k8s#85: a blue/green deploy tool shifts traffic weights across target groups on the live listener, and without ignore-field-drift the controller reconciles the weights back to the declared spec, breaking the deployment. TestListenerIgnoreFieldDrift.test_weight_drift_ignored declares a weighted forward action (90/10) annotated to ignore spec.defaultActions, shifts the weights out-of-band to 50/50 via ModifyListener, and asserts that the external distribution survives, the resource stays Synced, and a subsequent spec edit is retained in the CR but not pushed to AWS. The IgnoreFieldDrift feature gate is Alpha and disabled by default, so the test enables it on the deployed controller for the module and restores the prior value afterwards (mirrors the ec2-controller VPC coverage for the same runtime feature). The gate is only present once the controller's runtime dependency includes runtime#256, so this coverage runs green after the corresponding runtime bump. Two ip-type target groups back the weighted action so the fixture does not depend on registered targets. Signed-off-by: Hao Wang <rhaowang@amazon.com>
…90) ## Description Adds end-to-end coverage for the `services.k8s.aws/ignore-field-drift` annotation ([aws-controllers-k8s/runtime#256](aws-controllers-k8s/runtime#256)) on an ELBv2 `Listener`'s forward-action target-group weights. This mirrors **"Scenario 2"** of #85: a blue/green deploy tool shifts traffic weights across target groups on the live listener, and without ignore-field-drift the controller reconciles the weights back to the declared spec, breaking the deployment. The generic runtime feature lets the resource opt `spec.defaultActions` out of drift reconciliation via the annotation — no controller-specific code required. Test-only change: `test/e2e/tests/test_listener.py`, `test/e2e/resources/listener_ignore_field_drift.yaml`, `test/e2e/resources/target_group_ip.yaml`. ## What the test does `TestListenerIgnoreFieldDrift.test_weight_drift_ignored`: 1. Creates a `Listener` with a weighted forward action across two target groups (declared 90/10), annotated `services.k8s.aws/ignore-field-drift: "spec.defaultActions"`. 2. Asserts the declared weights were applied at create and the resource is `Synced`. 3. Shifts the weights out-of-band to 50/50 via `ModifyListener` (simulating the deploy tool). 4. Asserts the external distribution **survives** (controller does not revert), the resource **stays `Synced`**, and a subsequent spec edit (→70/30) is **retained in the CR but not pushed** to AWS. Two **ip-type** target groups back the weighted action so the fixture does not depend on registered targets. ## Feature gate handling The `IgnoreFieldDrift` gate is Alpha and disabled by default, so the test enables it on the deployed controller by patching `FEATURE_GATES` on the Deployment. The gate landed in **runtime v0.62.0**; `main` is now on v0.63.0, so it is available. The `ignore_field_drift_enabled` fixture is **session-scoped, check-then-set, and never restores** — this matters and is not just style. pytest-xdist spreads individual tests across 16 worker *processes* under `LoadScheduling`, so a fixture at *any* scope is instantiated once in every worker that picks up a test from this file. An enable/restore pair therefore rolls the shared controller Deployment twice per such worker, and each restart stops reconciliation cluster-wide long enough to fail an unrelated listener / load balancer / target group test waiting on `ACK.ResourceSynced`. This is the same fix as [ec2-controller#361](aws-controllers-k8s/ec2-controller#361) `b2cb92a`, where the module-scoped version cost three unrelated tests in one run. Check-then-set needs no cross-process lock: concurrent workers that both observe the gate off compute the same `FEATURE_GATES` string from the same starting value, so the second patch leaves the pod template byte-identical and does not bump the Deployment generation. Leaving the gate on is safe — it is inert unless a resource carries the annotation, and only this file's drift resources do; the kind cluster is torn down at the end of the run. Follow-up worth doing: set the gate at controller setup time (`FEATURE_GATES` in test-infra's `controller-setup.sh`, as `IAMRoleSelector` already does), after which this fixture degrades to a no-op check and the mid-run rollout disappears entirely. ## Testing Verified locally via a full `kind` e2e run with the gate enabled: `1 passed`. The external 50/50 shift survived, the resource stayed `Synced`, and the 70/30 spec edit was retained but not pushed. Note for anyone hitting this on an older base: against a runtime without the gate, the controller treats the unknown gate as fatal and exits, which surfaces only as `controller deployment ack-elbv2-controller did not roll out within 120s`. The crashlooping pod's logs are *not* in the prow `controller_logs` artifact (it captures the surviving pod), so that artifact looks misleadingly clean. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
Problem
The ACK ELBv2 controller treats the Kubernetes resource spec as the complete source of truth. During reconciliation, it reads the current state from AWS and forces it back to match the spec. This breaks setups where targets or traffic weights are managed externally:
Scenario 1 — Externally-registered targets
A separate controller (not ACK) registers targets with a target group that ACK manages. When the ACK TargetGroup spec has
targets: [](empty), the controller sees drift between spec (0 targets) and AWS (N targets) and deregisters all externally-registered targets.Scenario 2 — Blue/green weight shifting
A deployment tool shifts traffic weights between target groups (e.g., blue 100→0, green 0→100). On the next reconciliation, ACK sees the weight drift on the Listener's
DefaultActions.ForwardConfigand resets weights back to the spec values, breaking the active deployment.Solution
Two new annotations allow opting out of specific reconciliation behaviors:
elbv2.services.k8s.aws/target-management: ignore(TargetGroup)When set, the controller will not read, register, or deregister targets. Three guard points:
sdkFind— skipsDescribeTargetHealthsdkUpdate— skips register/deregister blocksdkCreate— skips post-create requeueelbv2.services.k8s.aws/weight-management: ignore(Listener)When set, the controller will not reconcile
ForwardConfig.TargetGroups[].Weight. Uses adelta_pre_comparehook that copies AWS-side weights into the desired spec before theDeepEqualcomparison runs:ModifyListenercall → external weights preservedModifyListenerIS called, but with AWS weights merged in → external weights preservedUsage
Files changed
Target group (target-management annotation)
pkg/resource/target_group/hooks.go— addedAnnotationTargetManagementconstant andisTargetManagementIgnored()helperpkg/resource/target_group/sdk.go— guards insdkFind,sdkCreate,sdkUpdatepkg/resource/target_group/hooks_test.go— 12 new test casestemplates/hooks/target_group/*.tpl— template files updated for future codegenListener (weight-management annotation)
pkg/resource/listener/hooks.go— addedcustomPreCompare,mergeLatestWeights,isWeightManagementIgnoredpkg/resource/listener/delta.go— addedcustomPreComparecall innewResourceDeltapkg/resource/listener/hooks_test.go— 11 new test cases (new file)generator.yaml— addeddelta_pre_comparehook for Listenerapis/v1alpha1/generator.yaml— same🤖 Generated with Claude Code