Skip to content

Conversation

zac-nixon
Copy link
Collaborator

Description

Adds a reconciler to process Gateway Class changes, including changes to LoadBalancer configurations attached to a Gateway Class.

Adds basic logic to ensure that Gateway reconciler will only progress Gateways that have an accepted Gateway Class.

Adds a configuration merger that implements merging logic to handle GatewayClass and Gateway LoadBalancer configs. [TODO: Add documentation]

Refactored to drop pointer references to the the lb config in the gateway model builders, this removes the need for nil checks in all of the model builders.

Checklist

  • Added tests that cover your change (if possible)
  • [] Added/modified documentation as required (such as the README.md, or the docs directory)
  • Manually tested
  • Made sure the title of the PR is a good description that can go into the release notes

BONUS POINTS checklist: complete for good vibes and maybe prizes?! 🤯

  • Backfilled missing tests for code in same general area 🎉
  • Refactored something and made the world a better place 🌟

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: zac-nixon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels May 1, 2025
merged.EnableICMP = lowPriority.Spec.EnableICMP
}

if highPriority.Spec.ManageBackendSecurityGroupRules != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish Go had ternary testing operation :(

mergingMode defines the merge behavior when both the Gateway and GatewayClass have a defined LoadBalancerConfiguration.
This field is only honored for the configuration attached to the GatewayClass.
enum:
- prefer-gateway
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am think should we be more specific in naming, cuz the name mergingMode does not imply it is for lbConfig and enum does not imply it too. Users can read doc for sure but maybe we can try to make name more explicit

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The merging mode only exists within the LoadBalancer configuration, I felt it would be redundant to re-state that the merging mode is specific to the LB.


func (h *enqueueRequestsForLoadBalancerConfigurationEvent) Delete(ctx context.Context, e event.TypedDeleteEvent[*elbv2gw.LoadBalancerConfiguration], queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
lbconfig := e.Object
h.logger.V(1).Info("enqueue loadbalancerconfiguration delete event", "loadbalancerconfiguration", lbconfig.Name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we also wanna logging namespace? (if name can be same for different namespace)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah good idea

}
}

func (merger *configMergerImpl) performTakeOneMerges(merged *elbv2gw.LoadBalancerConfigurationSpec, highPriority elbv2gw.LoadBalancerConfiguration, lowPriority elbv2gw.LoadBalancerConfiguration) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like in this function, it is assume if a property is not specified in highPriority spec, it will be specified in low priority spec, but what if lowPriority.Spec.LoadBalancerName is also nil (unless it is never gonna be the case), and if we originally have a default value for LoadBalancerName, then after this function, the default value will be overriden and it is gonna be nil

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow -- The merged spec starts off w/ a blank spec, so it's all zero values. We will always use the high priority value (if it exists) otherwise we use the low priority value, which could be a real value or a zero value. If it's a zero value, the merged spec still has a zero value which is correct.

I don't think it's possible we ever start with a default value for the load balancer name.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see, thanks for the explanation


func (r *gatewayReconciler) getLoadBalancerConfigForGateway(ctx context.Context, k8sClient client.Client, gw *gwv1.Gateway, gwClass *gwv1.GatewayClass) (elbv2gw.LoadBalancerConfiguration, error) {

// If the Gateway Class isn't accepted, we shouldn't try to reconcile this Gateway.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this check outside of this function in the main reconciler so that this function sticks to just getting the lb config.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

if storedVersion != nil {
safeVersion = *storedVersion
}
return elbv2gw.LoadBalancerConfiguration{}, errors.Errorf("GatewayClass [%s] hasn't processed latest loadbalancer config. Processed version %s, Latest version %s", gwClass.Name, safeVersion, gatewayClassLBConfig.ResourceVersion)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of throwing error, do we want to retry/wait for gwclass to complete its processing its cfg?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing an error is the same thing as wait + retry.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok got it.

@@ -62,7 +65,7 @@ func (h *enqueueRequestsForLoadBalancerConfigurationEvent) Generic(ctx context.C
}

func (h *enqueueRequestsForLoadBalancerConfigurationEvent) enqueueImpactedService(ctx context.Context, lbconfig *elbv2gw.LoadBalancerConfiguration, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
gwClasses := GetImpactedGatewayClassesFromLbConfig(ctx, h.k8sClient, lbconfig, h.gwController)
gwClasses := GetImpactedGatewayClassesFromLbConfig(ctx, h.k8sClient, lbconfig, h.gwControllerSet)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have separate controller for gateway class? Do we even need to enqueue gwclass for LB config changes in gateway controller?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

They serve two different purposes.

In the GatewayClass reconciler, it's meant to validate the configuration is valid and move the Gateway Class status to Accepted.

In the Gateway reconciler, it's meant to materialize the ELB resources according to the Gateway config.

}

func (h *enqueueRequestsForLoadBalancerConfigurationEvent) Create(ctx context.Context, e event.TypedCreateEvent[*elbv2gw.LoadBalancerConfiguration], queue workqueue.TypedRateLimitingInterface[reconcile.Request]) {
// We don't need to respond to create events.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the gwclass is created first referencing a non-existing cfg, user realises his mistake as they see not found status on the gwclass and decides to create the lbcfg now? We need to listen to this event and enqueue the gwclass referencing it to update its status.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should already been handled, because we have the event queued for the gwclass creation. Since it failed to find the config, it will keep reconciling. Eventually when the config is created, everything should just work.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 1, 2025
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 2, 2025
@shraddhabang
Copy link
Collaborator

/lgtm
/approved

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 2, 2025
@k8s-ci-robot k8s-ci-robot merged commit a3c4fc6 into kubernetes-sigs:main May 2, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants