From ee1fbab973f029e2a3ee935510bca461d17a62d8 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Thu, 12 Oct 2023 19:04:47 +0200 Subject: [PATCH] temp reconcile merged service and deployment Signed-off-by: Karol Szwaj --- .../kubernetes/proxy/resource.go | 6 +-- internal/provider/kubernetes/controller.go | 15 ++++-- internal/provider/kubernetes/helpers.go | 12 ++++- internal/provider/kubernetes/predicates.go | 47 +++++++++++++++++-- .../provider/kubernetes/predicates_test.go | 2 +- 5 files changed, 67 insertions(+), 15 deletions(-) diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index 454b4dde29e6..de1d3fae8588 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -57,8 +57,8 @@ func ExpectedResourceHashedName(name string) string { return fmt.Sprintf("%s-%s", config.EnvoyPrefix, hashedName) } -// ExpectedServiceHashedName returns expected service name with max length of 15 characters. -func ExpectedServiceHashedName(name string) string { +// ExpectedContainerPortHashedName returns expected service name with max length of 15 characters. +func ExpectedContainerPortHashedName(name string) string { if len(name) > 15 { hashedName := providerutils.HashString(name) listenerName := strings.Split(name, "-") @@ -114,7 +114,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, deploymentConfig *egv1a1.Kube return nil, fmt.Errorf("invalid protocol %q", p.Protocol) } port := corev1.ContainerPort{ - Name: ExpectedServiceHashedName(p.Name), + Name: ExpectedContainerPortHashedName(p.Name), ContainerPort: p.ContainerPort, Protocol: protocol, } diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index dc7f1b3e6d1d..e3a3fde5c765 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -403,16 +403,20 @@ func (r *gatewayAPIReconciler) statusUpdateForGateway(ctx context.Context, gtw * if r.statusUpdater == nil { return } - + var merged bool + res, _ := r.resources.GatewayAPIResources.Load(string(gtw.Spec.GatewayClassName)) + if res.EnvoyProxy != nil && res.EnvoyProxy.Spec.MergeGateways != nil && *res.EnvoyProxy.Spec.MergeGateways { + merged = true + } // Get deployment - deploy, err := r.envoyDeploymentForGateway(ctx, gtw) + deploy, err := r.envoyDeploymentForGateway(ctx, gtw, merged) if err != nil { r.log.Info("failed to get Deployment for gateway", "namespace", gtw.Namespace, "name", gtw.Name) } // Get service - svc, err := r.envoyServiceForGateway(ctx, gtw) + svc, err := r.envoyServiceForGateway(ctx, gtw, merged) if err != nil { r.log.Info("failed to get Service for gateway", "namespace", gtw.Namespace, "name", gtw.Name) @@ -1317,7 +1321,10 @@ func (r *gatewayAPIReconciler) watchResources(ctx context.Context, mgr manager.M } // Watch Gateway CRUDs and reconcile affected GatewayClass. - gPredicates := []predicate.Predicate{predicate.NewPredicateFuncs(r.validateGatewayForReconcile)} + gPredicates := []predicate.Predicate{ + predicate.NewPredicateFuncs(r.validateGatewayForReconcile), + predicate.GenerationChangedPredicate{}, + } if len(r.namespaceLabels) != 0 { gPredicates = append(gPredicates, predicate.NewPredicateFuncs(r.hasMatchingNamespaceLabels)) } diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go index 0eb497f1c356..7ddfee39e35e 100644 --- a/internal/provider/kubernetes/helpers.go +++ b/internal/provider/kubernetes/helpers.go @@ -197,12 +197,20 @@ func refsSecret(ref *gwapiv1b1.SecretObjectReference) bool { (ref.Kind == nil || *ref.Kind == gatewayapi.KindSecret) } -func infraServiceName(gateway *gwapiv1b1.Gateway) string { +func infraServiceName(gateway *gwapiv1b1.Gateway, merged bool) string { + if merged { + infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) + return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + } infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) } -func infraDeploymentName(gateway *gwapiv1b1.Gateway) string { +func infraDeploymentName(gateway *gwapiv1b1.Gateway, merged bool) string { + if merged { + infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) + return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + } infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) } diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 746f99c5ee32..b00da15bf0f1 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -168,7 +168,20 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) return false } + labels := svc.GetLabels() + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + if ok { + gtw := r.findGateways(ctx, gclass) + if len(gtw.Items) != 0 { + for _, gw := range gtw.Items { + gw := gw + r.statusUpdateForGateway(ctx, &gw) + } + } + nsName := utils.NamespacedName(svc) + return r.isRouteReferencingBackend(&nsName) + } // Check if the Service belongs to a Gateway, if so, update the Gateway status. gtw := r.findOwningGateway(ctx, svc.GetLabels()) if gtw != nil { @@ -180,6 +193,19 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return r.isRouteReferencingBackend(&nsName) } +// findGateways attempts finds a GatewayList using accepted GatewayClass name. +func (r *gatewayAPIReconciler) findGateways(ctx context.Context, class string) *gwapiv1b1.GatewayList { + gatewayList := &gwapiv1b1.GatewayList{} + if err := r.client.List(ctx, gatewayList, &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(classGatewayIndex, class), + }); err != nil { + r.log.Info("no associated Gateways found for GatewayClass", "name", class) + return nil + } + + return gatewayList +} + // validateServiceImportForReconcile tries finding the owning Gateway of the ServiceImport // if it exists, finds the Gateway's Deployment, and further updates the Gateway // status Ready condition. All Services are pushed for reconciliation. @@ -286,7 +312,18 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) return false } - + labels := deployment.GetLabels() + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + if ok { + gtw := r.findGateways(ctx, gclass) + if len(gtw.Items) != 0 { + for _, gw := range gtw.Items { + gw := gw + r.statusUpdateForGateway(ctx, &gw) + } + } + return false + } // Only deployments in the configured namespace should be reconciled. if deployment.Namespace == r.namespace { // Check if the deployment belongs to a Gateway, if so, update the Gateway status. @@ -374,10 +411,10 @@ func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gw } // envoyDeploymentForGateway returns the Envoy Deployment, returning nil if the Deployment doesn't exist. -func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*appsv1.Deployment, error) { +func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*appsv1.Deployment, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraDeploymentName(gateway), + Name: infraDeploymentName(gateway, merged), } deployment := new(appsv1.Deployment) if err := r.client.Get(ctx, key, deployment); err != nil { @@ -390,10 +427,10 @@ func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, ga } // envoyServiceForGateway returns the Envoy service, returning nil if the service doesn't exist. -func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*corev1.Service, error) { +func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*corev1.Service, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraServiceName(gateway), + Name: infraServiceName(gateway, merged), } svc := new(corev1.Service) if err := r.client.Get(ctx, key, svc); err != nil { diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 6d156f083ed3..27e73fe6dc74 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -334,7 +334,7 @@ func TestValidateServiceForReconcile(t *testing.T) { configs: []client.Object{ test.GetGatewayClass("test-gc", v1alpha1.GatewayControllerName), sampleGateway, - test.GetGatewayDeployment(types.NamespacedName{Name: infraDeploymentName(sampleGateway)}, nil), + test.GetGatewayDeployment(types.NamespacedName{Name: infraDeploymentName(sampleGateway, false)}, nil), }, service: test.GetService(types.NamespacedName{Name: "service"}, map[string]string{ gatewayapi.OwningGatewayNameLabel: "scheduled-status-test",