Skip to content

Commit b9d8bdb

Browse files
committed
Refactors initial commit
Signed-off-by: Daneyon Hansen <[email protected]>
1 parent 892d2d7 commit b9d8bdb

File tree

19 files changed

+213
-130
lines changed

19 files changed

+213
-130
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
changelog:
2-
- type: NEW_FEATURE
2+
- type: FIX
33
issueLink: https://github.com/solo-io/gloo/issues/10092
44
resolvesIssue: true
55
description: >-
66
Adds support for the GatewayClass `SupportedVersion` status condition and updates the ReconcileGatewayClasses()
7-
method to manage status conditions according to the Gateway API specification. The gateway controller will now
8-
reconcile supported Gateway API CRDs and set the `SupportedVersion` status condition based on the value of the
9-
`gateway.networking.k8s.io/bundle-version` annotation.
7+
method to manage status conditions according to the Gateway API specification. The gateway controller will
8+
reconcile supported Gateway API CRDs and set the GatewayClass `SupportedVersion` status condition based on the
9+
value of the `gateway.networking.k8s.io/bundle-version` annotation.

pkg/schemes/extended_scheme.go

+12-27
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
package schemes
22

33
import (
4+
"context"
45
"fmt"
56

6-
"github.com/solo-io/gloo/projects/gateway2/wellknown"
7-
"k8s.io/apimachinery/pkg/api/meta"
7+
istiokube "istio.io/istio/pkg/kube"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89
"k8s.io/apimachinery/pkg/runtime"
9-
"k8s.io/client-go/discovery"
10-
"k8s.io/client-go/rest"
11-
1210
gwv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
11+
12+
"github.com/solo-io/gloo/projects/gateway2/crds"
13+
"github.com/solo-io/gloo/projects/gateway2/wellknown"
1314
)
1415

1516
// AddGatewayV1A2Scheme adds the gwv1a2 scheme to the provided scheme if the TCPRoute CRD exists.
16-
func AddGatewayV1A2Scheme(restConfig *rest.Config, scheme *runtime.Scheme) error {
17-
exists, err := CRDExists(restConfig, gwv1a2.GroupVersion.Group, gwv1a2.GroupVersion.Version, wellknown.TCPRouteKind)
17+
func AddGatewayV1A2Scheme(ctx context.Context, cli istiokube.Client, scheme *runtime.Scheme) error {
18+
exists, err := crdExists(ctx, cli, crds.TCPRoute)
1819
if err != nil {
1920
return fmt.Errorf("error checking if %s CRD exists: %w", wellknown.TCPRouteKind, err)
2021
}
@@ -28,27 +29,11 @@ func AddGatewayV1A2Scheme(restConfig *rest.Config, scheme *runtime.Scheme) error
2829
return nil
2930
}
3031

31-
// Helper function to check if a CRD exists
32-
func CRDExists(restConfig *rest.Config, group, version, kind string) (bool, error) {
33-
discoveryClient, err := discovery.NewDiscoveryClientForConfig(restConfig)
32+
// crdExists queries the Kubernetes API for the provided CRD name.
33+
func crdExists(ctx context.Context, cli istiokube.Client, name string) (bool, error) {
34+
_, err := cli.Dynamic().Resource(crds.GVR).Get(ctx, name, metav1.GetOptions{})
3435
if err != nil {
3536
return false, err
3637
}
37-
38-
groupVersion := fmt.Sprintf("%s/%s", group, version)
39-
apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(groupVersion)
40-
if err != nil {
41-
if discovery.IsGroupDiscoveryFailedError(err) || meta.IsNoMatchError(err) {
42-
return false, nil
43-
}
44-
return false, err
45-
}
46-
47-
for _, apiResource := range apiResourceList.APIResources {
48-
if apiResource.Kind == kind {
49-
return true, nil
50-
}
51-
}
52-
53-
return false, nil
38+
return true, nil
5439
}

projects/controller/cli/pkg/cmd/install/kubegateway/install.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/solo-io/gloo/pkg/utils/kubeutils"
88
"github.com/solo-io/gloo/projects/controller/cli/pkg/cmd/options"
99
"github.com/solo-io/gloo/projects/controller/cli/pkg/kubegatewayutils"
10-
"github.com/solo-io/gloo/projects/gateway2/crds"
10+
"github.com/solo-io/gloo/projects/gateway2/crds/experimental"
1111
"github.com/solo-io/gloo/projects/gateway2/deployer"
1212
"helm.sh/helm/v3/pkg/cli"
1313
"helm.sh/helm/v3/pkg/cli/values"
@@ -64,7 +64,7 @@ func install(opts *options.Options, installOpts *Options) error {
6464

6565
if !crdsExist {
6666
fmt.Printf("Applying Gateway CRDs... ")
67-
crds, err := deployer.ConvertYAMLToObjects(cli.Scheme(), crds.GatewayCrds)
67+
crds, err := deployer.ConvertYAMLToObjects(cli.Scheme(), experimental.GatewayCrds)
6868
if err != nil {
6969
fmt.Printf("Failed\n")
7070
return err

projects/controller/cli/pkg/cmd/install/kubegateway/uninstall.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/solo-io/gloo/pkg/utils/kubeutils"
88

99
"github.com/solo-io/gloo/projects/controller/cli/pkg/cmd/options"
10-
"github.com/solo-io/gloo/projects/gateway2/crds"
10+
"github.com/solo-io/gloo/projects/gateway2/crds/experimental"
1111
"github.com/solo-io/gloo/projects/gateway2/deployer"
1212
corev1 "k8s.io/api/core/v1"
1313
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -51,7 +51,7 @@ func uninstall(opts *options.Options, installOpts *Options) error {
5151
}
5252

5353
fmt.Printf("Deleting Gateway CRDs... ")
54-
crds, err := deployer.ConvertYAMLToObjects(cli.Scheme(), crds.GatewayCrds)
54+
crds, err := deployer.ConvertYAMLToObjects(cli.Scheme(), experimental.GatewayCrds)
5555
if err != nil {
5656
fmt.Printf("Failed\n")
5757
} else {

projects/gateway2/controller/controller.go

+62-37
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"maps"
78
"strings"
89

910
corev1 "k8s.io/api/core/v1"
1011
discoveryv1 "k8s.io/api/discovery/v1"
1112
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
12-
kerrors "k8s.io/apimachinery/pkg/api/errors"
1313
"k8s.io/apimachinery/pkg/api/meta"
1414
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1515
"k8s.io/apimachinery/pkg/fields"
@@ -61,8 +61,8 @@ type GatewayConfig struct {
6161
Aws *deployer.AwsInfo
6262

6363
Extensions extensions.K8sGatewayExtensions
64-
// CRDs defines the set of discovered Gateway API CRDs
65-
CRDs sets.Set[string]
64+
// CRDs is a map of supported Gateway API CRDs with the discovered annotations for each.
65+
CRDs *crds.CrdToAnnotation
6666
}
6767

6868
func NewBaseGatewayController(ctx context.Context, cfg GatewayConfig) error {
@@ -76,6 +76,7 @@ func NewBaseGatewayController(ctx context.Context, cfg GatewayConfig) error {
7676
cli: cfg.Mgr.GetClient(),
7777
scheme: cfg.Mgr.GetScheme(),
7878
kick: cfg.Kick,
79+
crds: cfg.CRDs,
7980
},
8081
}
8182

@@ -135,9 +136,11 @@ func (c *controllerBuilder) addIndexes(ctx context.Context) error {
135136
}
136137

137138
// Conditionally index for TCPRoute
138-
if c.cfg.CRDs.Has(wellknown.TCPRouteCRD) {
139-
if err := c.cfg.Mgr.GetFieldIndexer().IndexField(ctx, &apiv1a2.TCPRoute{}, query.TcpRouteTargetField, query.IndexerByObjType); err != nil {
140-
errs = append(errs, err)
139+
if c.cfg.CRDs != nil {
140+
if _, exists := (*c.cfg.CRDs)[crds.TCPRoute]; exists {
141+
if err := c.cfg.Mgr.GetFieldIndexer().IndexField(ctx, &apiv1a2.TCPRoute{}, query.TcpRouteTargetField, query.IndexerByObjType); err != nil {
142+
errs = append(errs, err)
143+
}
141144
}
142145
}
143146

@@ -297,8 +300,8 @@ func (c *controllerBuilder) watchGwClass(_ context.Context) error {
297300
Complete(reconcile.Func(c.reconciler.ReconcileGatewayClasses))
298301
}
299302

300-
// watchCustomResourceDefinitions sets up a controller to watch for changes to specific Gateway API
301-
// CRDs and triggers GatewayClass reconciliation if generation or annotations change.
303+
// watchCRDs sets up a controller to watch for changes to supported Gateway API CRDs
304+
// and triggers GatewayClass reconciliation if generation or annotations change.
302305
func (c *controllerBuilder) watchCRDs(_ context.Context) error {
303306
return ctrl.NewControllerManagedBy(c.cfg.Mgr).
304307
For(&apiextv1.CustomResourceDefinition{}).
@@ -308,7 +311,20 @@ func (c *controllerBuilder) watchCRDs(_ context.Context) error {
308311
return false
309312
}
310313
// Check if the CRD is one we care about
311-
return c.cfg.CRDs.Has(crd.Name)
314+
if !crds.IsSupported(crd.Name) {
315+
return false
316+
}
317+
// Maintain the set of supported CRDs
318+
if c.cfg.CRDs != nil {
319+
annotations, exist := (*c.cfg.CRDs)[crd.Name]
320+
if !exist {
321+
(*c.cfg.CRDs)[crd.Name] = make(map[string]string)
322+
}
323+
if !maps.Equal(annotations, crd.Annotations) {
324+
(*c.cfg.CRDs)[crd.Name] = crd.Annotations
325+
}
326+
}
327+
return true
312328
})).
313329
WithEventFilter(predicate.Or(
314330
predicate.AnnotationChangedPredicate{},
@@ -325,8 +341,13 @@ func (c *controllerBuilder) watchHttpRoute(_ context.Context) error {
325341
}
326342

327343
func (c *controllerBuilder) watchTcpRoute(ctx context.Context) error {
328-
if !c.cfg.CRDs.Has(wellknown.TCPRouteCRD) {
329-
log.FromContext(ctx).Info("TCPRoute type not registered in scheme; skipping TCPRoute controller setup")
344+
log := log.FromContext(ctx)
345+
346+
if c.cfg.CRDs == nil {
347+
log.Info("CRD annotations map not initialized; skipping TCPRoute controller setup")
348+
}
349+
if _, exists := (*c.cfg.CRDs)[crds.TCPRoute]; !exists {
350+
log.Info("TCPRoute type not registered in scheme; skipping TCPRoute controller setup")
330351
return nil
331352
}
332353

@@ -424,6 +445,8 @@ type controllerReconciler struct {
424445
cli client.Client
425446
scheme *runtime.Scheme
426447
kick func(ctx context.Context)
448+
// crds is a map of supported Gateway API CRDs with the discovered annotations for each.
449+
crds *crds.CrdToAnnotation
427450
}
428451

429452
func (r *controllerReconciler) ReconcileHttpListenerOptions(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
@@ -576,32 +599,25 @@ func (r *controllerReconciler) ReconcileGatewayClasses(ctx context.Context, req
576599
log.Info("Reconciling GatewayClass")
577600

578601
// Initialize the status conditions. No need to set LastTransitionTime since it's handled by SetStatusCondition.
579-
msg := "Gateway API CRDs are a supported version"
580602
acceptedCondition := metav1.Condition{
581603
Type: string(apiv1.GatewayClassConditionStatusAccepted),
582604
Status: metav1.ConditionTrue,
583605
Reason: string(apiv1.GatewayClassReasonAccepted),
584-
Message: msg,
606+
Message: "All dependencies have been met",
585607
ObservedGeneration: gwclass.Generation,
586608
}
587609
supportedCondition := metav1.Condition{
588610
Type: string(apiv1.GatewayClassConditionStatusSupportedVersion),
589611
Status: metav1.ConditionTrue,
590612
Reason: string(apiv1.GatewayClassReasonSupportedVersion),
591-
Message: msg,
613+
Message: "Gateway API CRDs are a supported version",
592614
ObservedGeneration: gwclass.Generation,
593615
}
594616

595-
// Check CRD versions
596-
supported, err := r.checkCRDVersions(ctx)
597-
if err != nil {
598-
log.Error(err, "Failed to check CRD versions")
599-
return ctrl.Result{}, err
600-
}
601-
602-
if !supported {
617+
// Set status conditions based on observed CRD versions
618+
if !r.crdsSupportedVersion(ctx) {
603619
// Update the values of status conditions
604-
msg = fmt.Sprintf("Unsupported Gateway API CRDs detected. Supported versions are: %s",
620+
msg := fmt.Sprintf("Unsupported Gateway API CRDs detected. Supported versions are: %s",
605621
strings.Join(wellknown.SupportedVersions, ", "))
606622
acceptedCondition.Status = metav1.ConditionFalse
607623
acceptedCondition.Reason = string(apiv1.GatewayClassReasonUnsupportedVersion)
@@ -625,22 +641,31 @@ func (r *controllerReconciler) ReconcileGatewayClasses(ctx context.Context, req
625641
return ctrl.Result{}, nil
626642
}
627643

628-
// checkCRDVersions checks that the "gateway.networking.k8s.io/bundle-version" annotation key is set
629-
// to a supported version for each required Gateway API CRD.
630-
func (r *controllerReconciler) checkCRDVersions(ctx context.Context) (bool, error) {
631-
for _, crdName := range crds.Required {
632-
crd := &apiextv1.CustomResourceDefinition{}
633-
if err := r.cli.Get(ctx, client.ObjectKey{Name: crdName}, crd); err != nil {
634-
if kerrors.IsNotFound(err) {
635-
return false, nil
636-
}
637-
return false, err
644+
// crdsSupportedVersion returns true if the "gateway.networking.k8s.io/bundle-version" annotation key is
645+
// set to a supported version for each managed Gateway API CRD.
646+
func (r *controllerReconciler) crdsSupportedVersion(ctx context.Context) bool {
647+
log := log.FromContext(ctx)
648+
649+
if r.crds == nil {
650+
return false
651+
}
652+
653+
for crdName, annotations := range *r.crds {
654+
if annotations == nil || len(annotations) == 0 {
655+
log.Info("no annotations found for CRD", "name", crdName)
656+
return false
638657
}
639658

640-
bundleVersion, exists := crd.Annotations[consts.BundleVersionAnnotation]
641-
if !exists || !crds.IsSupportedVersion(bundleVersion) {
642-
return false, nil
659+
bundleVersion, exists := annotations[consts.BundleVersionAnnotation]
660+
if !exists {
661+
log.Info("bundle version annotation does not exist for CRD", "name", crdName)
662+
return false
663+
}
664+
if !crds.IsSupportedVersion(bundleVersion) {
665+
log.Info("bundle version annotation not a supported version for CRD", "name", crdName, "version", bundleVersion)
666+
return false
643667
}
644668
}
645-
return true, nil
669+
670+
return true
646671
}

projects/gateway2/controller/controller_suite_test.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ import (
1717
. "github.com/onsi/gomega"
1818
"github.com/solo-io/gloo/projects/gateway2/api/v1alpha1"
1919
"github.com/solo-io/gloo/projects/gateway2/controller"
20+
"github.com/solo-io/gloo/projects/gateway2/crds"
2021
"github.com/solo-io/gloo/projects/gateway2/extensions"
22+
"github.com/solo-io/gloo/projects/gateway2/setup"
2123
"github.com/solo-io/gloo/projects/gateway2/wellknown"
24+
istiokube "istio.io/istio/pkg/kube"
2225
corev1 "k8s.io/api/core/v1"
2326
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2427
"k8s.io/apimachinery/pkg/util/sets"
@@ -38,6 +41,7 @@ import (
3841
var (
3942
cfg *rest.Config
4043
k8sClient client.Client
44+
i8sClient istiokube.Client
4145
testEnv *envtest.Environment
4246
ctx context.Context
4347
cancel context.CancelFunc
@@ -86,11 +90,16 @@ var _ = BeforeSuite(func() {
8690
cfg, err = testEnv.Start()
8791
Expect(err).NotTo(HaveOccurred())
8892
Expect(cfg).NotTo(BeNil())
89-
scheme := schemes.DefaultScheme()
93+
94+
scheme := schemes.TestingScheme()
9095
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
9196
Expect(err).NotTo(HaveOccurred())
9297
Expect(k8sClient).NotTo(BeNil())
9398

99+
i8sClient, err = setup.CreateKubeClient(cfg)
100+
Expect(err).NotTo(HaveOccurred())
101+
Expect(i8sClient).NotTo(BeNil())
102+
94103
webhookInstallOptions := &testEnv.WebhookInstallOptions
95104
mgrOpts := ctrl.Options{
96105
Scheme: scheme,
@@ -117,13 +126,19 @@ var _ = BeforeSuite(func() {
117126
Mgr: mgr,
118127
})
119128
Expect(err).ToNot(HaveOccurred())
129+
130+
crdMap, err := crds.GetGatewayCRDs(ctx, i8sClient)
131+
Expect(err).ToNot(HaveOccurred())
132+
Expect(crdMap).NotTo(BeNil())
133+
120134
cfg := controller.GatewayConfig{
121135
Mgr: mgr,
122136
ControllerName: gatewayControllerName,
123137
GWClasses: gwClasses,
124138
AutoProvision: true,
125139
Kick: func(ctx context.Context) { return },
126140
Extensions: exts,
141+
CRDs: crdMap,
127142
}
128143
err = controller.NewBaseGatewayController(ctx, cfg)
129144
Expect(err).ToNot(HaveOccurred())

0 commit comments

Comments
 (0)