Do not update route status when nothing changed
This commit is contained in:
parent
386c2ffb20
commit
7dbd3f88f6
5 changed files with 116 additions and 63 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
|
|||
type Client interface {
|
||||
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
UpdateGatewayStatus(ctx context.Context, gateway ktypes.NamespacedName, status gatev1.GatewayStatus) error
|
||||
UpdateGatewayClassStatus(ctx context.Context, name string, condition metav1.Condition) error
|
||||
UpdateGatewayClassStatus(ctx context.Context, name string, status gatev1.GatewayClassStatus) error
|
||||
UpdateHTTPRouteStatus(ctx context.Context, route ktypes.NamespacedName, status gatev1.HTTPRouteStatus) error
|
||||
UpdateTCPRouteStatus(ctx context.Context, route ktypes.NamespacedName, status gatev1alpha2.TCPRouteStatus) error
|
||||
UpdateTLSRouteStatus(ctx context.Context, route ktypes.NamespacedName, status gatev1alpha2.TLSRouteStatus) error
|
||||
|
@ -378,7 +379,7 @@ func (c *clientWrapper) ListGatewayClasses() ([]*gatev1.GatewayClass, error) {
|
|||
return c.factoryGatewayClass.Gateway().V1().GatewayClasses().Lister().List(labels.Everything())
|
||||
}
|
||||
|
||||
func (c *clientWrapper) UpdateGatewayClassStatus(ctx context.Context, name string, condition metav1.Condition) error {
|
||||
func (c *clientWrapper) UpdateGatewayClassStatus(ctx context.Context, name string, status gatev1.GatewayClassStatus) error {
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
currentGatewayClass, err := c.factoryGatewayClass.Gateway().V1().GatewayClasses().Lister().Get(name)
|
||||
if err != nil {
|
||||
|
@ -387,23 +388,12 @@ func (c *clientWrapper) UpdateGatewayClassStatus(ctx context.Context, name strin
|
|||
return err
|
||||
}
|
||||
|
||||
currentGatewayClass = currentGatewayClass.DeepCopy()
|
||||
var newConditions []metav1.Condition
|
||||
for _, cond := range currentGatewayClass.Status.Conditions {
|
||||
// No update for identical condition.
|
||||
if cond.Type == condition.Type && cond.Status == condition.Status && cond.ObservedGeneration == condition.ObservedGeneration {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Keep other condition types.
|
||||
if cond.Type != condition.Type {
|
||||
newConditions = append(newConditions, cond)
|
||||
}
|
||||
if conditionsEqual(currentGatewayClass.Status.Conditions, status.Conditions) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append the condition to update.
|
||||
newConditions = append(newConditions, condition)
|
||||
currentGatewayClass.Status.Conditions = newConditions
|
||||
currentGatewayClass = currentGatewayClass.DeepCopy()
|
||||
currentGatewayClass.Status = status
|
||||
|
||||
if _, err = c.csGateway.GatewayV1().GatewayClasses().UpdateStatus(ctx, currentGatewayClass, metav1.UpdateOptions{}); err != nil {
|
||||
// We have to return err itself here (not wrapped inside another error)
|
||||
|
@ -433,7 +423,7 @@ func (c *clientWrapper) UpdateGatewayStatus(ctx context.Context, gateway ktypes.
|
|||
return err
|
||||
}
|
||||
|
||||
if gatewayStatusEquals(currentGateway.Status, status) {
|
||||
if gatewayStatusEqual(currentGateway.Status, status) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -468,16 +458,22 @@ func (c *clientWrapper) UpdateHTTPRouteStatus(ctx context.Context, route ktypes.
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: keep statuses for gateways managed by other Traefik instances.
|
||||
var parentStatuses []gatev1.RouteParentStatus
|
||||
for _, currentParentStatus := range currentRoute.Status.Parents {
|
||||
if currentParentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, currentParentStatus)
|
||||
parentStatuses := make([]gatev1.RouteParentStatus, len(status.Parents))
|
||||
copy(parentStatuses, status.Parents)
|
||||
|
||||
// keep statuses added by other gateway controllers.
|
||||
// TODO: we should also keep statuses for gateways managed by other Traefik instances.
|
||||
for _, parentStatus := range currentRoute.Status.Parents {
|
||||
if parentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, parentStatus)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
parentStatuses = append(parentStatuses, status.Parents...)
|
||||
// do not update status when nothing has changed.
|
||||
if routeParentStatusesEqual(currentRoute.Status.Parents, parentStatuses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentRoute = currentRoute.DeepCopy()
|
||||
currentRoute.Status = gatev1.HTTPRouteStatus{
|
||||
|
@ -514,16 +510,22 @@ func (c *clientWrapper) UpdateTCPRouteStatus(ctx context.Context, route ktypes.N
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: keep statuses for gateways managed by other Traefik instances.
|
||||
var parentStatuses []gatev1alpha2.RouteParentStatus
|
||||
for _, currentParentStatus := range currentRoute.Status.Parents {
|
||||
if currentParentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, currentParentStatus)
|
||||
parentStatuses := make([]gatev1.RouteParentStatus, len(status.Parents))
|
||||
copy(parentStatuses, status.Parents)
|
||||
|
||||
// keep statuses added by other gateway controllers.
|
||||
// TODO: we should also keep statuses for gateways managed by other Traefik instances.
|
||||
for _, parentStatus := range currentRoute.Status.Parents {
|
||||
if parentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, parentStatus)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
parentStatuses = append(parentStatuses, status.Parents...)
|
||||
// do not update status when nothing has changed.
|
||||
if routeParentStatusesEqual(currentRoute.Status.Parents, parentStatuses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentRoute = currentRoute.DeepCopy()
|
||||
currentRoute.Status = gatev1alpha2.TCPRouteStatus{
|
||||
|
@ -560,16 +562,22 @@ func (c *clientWrapper) UpdateTLSRouteStatus(ctx context.Context, route ktypes.N
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: keep statuses for gateways managed by other Traefik instances.
|
||||
var parentStatuses []gatev1alpha2.RouteParentStatus
|
||||
for _, currentParentStatus := range currentRoute.Status.Parents {
|
||||
if currentParentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, currentParentStatus)
|
||||
parentStatuses := make([]gatev1.RouteParentStatus, len(status.Parents))
|
||||
copy(parentStatuses, status.Parents)
|
||||
|
||||
// keep statuses added by other gateway controllers.
|
||||
// TODO: we should also keep statuses for gateways managed by other Traefik instances.
|
||||
for _, parentStatus := range currentRoute.Status.Parents {
|
||||
if parentStatus.ControllerName != controllerName {
|
||||
parentStatuses = append(parentStatuses, parentStatus)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
parentStatuses = append(parentStatuses, status.Parents...)
|
||||
// do not update status when nothing has changed.
|
||||
if routeParentStatusesEqual(currentRoute.Status.Parents, parentStatuses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
currentRoute = currentRoute.DeepCopy()
|
||||
currentRoute.Status = gatev1alpha2.TLSRouteStatus{
|
||||
|
@ -675,12 +683,12 @@ func translateNotFoundError(err error) (bool, error) {
|
|||
return err == nil, err
|
||||
}
|
||||
|
||||
func gatewayStatusEquals(statusA, statusB gatev1.GatewayStatus) bool {
|
||||
func gatewayStatusEqual(statusA, statusB gatev1.GatewayStatus) bool {
|
||||
if len(statusA.Listeners) != len(statusB.Listeners) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !conditionsEquals(statusA.Conditions, statusB.Conditions) {
|
||||
if !conditionsEqual(statusA.Conditions, statusB.Conditions) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -688,7 +696,7 @@ func gatewayStatusEquals(statusA, statusB gatev1.GatewayStatus) bool {
|
|||
for _, newListener := range statusB.Listeners {
|
||||
for _, oldListener := range statusA.Listeners {
|
||||
if newListener.Name == oldListener.Name {
|
||||
if !conditionsEquals(newListener.Conditions, oldListener.Conditions) {
|
||||
if !conditionsEqual(newListener.Conditions, oldListener.Conditions) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -704,22 +712,48 @@ func gatewayStatusEquals(statusA, statusB gatev1.GatewayStatus) bool {
|
|||
return listenerMatches == len(statusA.Listeners)
|
||||
}
|
||||
|
||||
func conditionsEquals(conditionsA, conditionsB []metav1.Condition) bool {
|
||||
if len(conditionsA) != len(conditionsB) {
|
||||
func routeParentStatusesEqual(routeParentStatusesA, routeParentStatusesB []gatev1alpha2.RouteParentStatus) bool {
|
||||
if len(routeParentStatusesA) != len(routeParentStatusesB) {
|
||||
return false
|
||||
}
|
||||
|
||||
conditionMatches := 0
|
||||
for _, conditionA := range conditionsA {
|
||||
for _, conditionB := range conditionsB {
|
||||
if conditionA.Type == conditionB.Type {
|
||||
if conditionA.Reason != conditionB.Reason || conditionA.Status != conditionB.Status || conditionA.Message != conditionB.Message || conditionA.ObservedGeneration != conditionB.ObservedGeneration {
|
||||
return false
|
||||
}
|
||||
conditionMatches++
|
||||
}
|
||||
for _, sA := range routeParentStatusesA {
|
||||
if !slices.ContainsFunc(routeParentStatusesB, func(sB gatev1alpha2.RouteParentStatus) bool {
|
||||
return routeParentStatusEqual(sB, sA)
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return conditionMatches == len(conditionsA)
|
||||
for _, sB := range routeParentStatusesB {
|
||||
if !slices.ContainsFunc(routeParentStatusesA, func(sA gatev1alpha2.RouteParentStatus) bool {
|
||||
return routeParentStatusEqual(sA, sB)
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func routeParentStatusEqual(sA, sB gatev1alpha2.RouteParentStatus) bool {
|
||||
if !reflect.DeepEqual(sA.ParentRef, sB.ParentRef) {
|
||||
return false
|
||||
}
|
||||
|
||||
if sA.ControllerName != sB.ControllerName {
|
||||
return false
|
||||
}
|
||||
|
||||
return conditionsEqual(sA.Conditions, sB.Conditions)
|
||||
}
|
||||
|
||||
func conditionsEqual(conditionsA, conditionsB []metav1.Condition) bool {
|
||||
return slices.EqualFunc(conditionsA, conditionsB, func(cA metav1.Condition, cB metav1.Condition) bool {
|
||||
return cA.Type == cB.Type &&
|
||||
cA.Reason == cB.Reason &&
|
||||
cA.Status == cB.Status &&
|
||||
cA.Message == cB.Message &&
|
||||
cA.ObservedGeneration == cB.ObservedGeneration
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue