Skip to content

Commit

Permalink
chore: move and publish CRD checker (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
rainest committed Apr 25, 2024
1 parent 9015ff6 commit 649afca
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 51 deletions.
49 changes: 2 additions & 47 deletions modules/manager/controller_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ package manager

import (
"context"
"errors"
"fmt"
"net/url"
"reflect"

"github.com/samber/lo"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
Expand All @@ -28,6 +23,7 @@ import (
"github.com/kong/gateway-operator/internal/utils/index"
dataplanevalidator "github.com/kong/gateway-operator/internal/validation/dataplane"
"github.com/kong/gateway-operator/pkg/consts"
k8sutils "github.com/kong/gateway-operator/pkg/utils/kubernetes"
)

const (
Expand Down Expand Up @@ -145,7 +141,7 @@ func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef,
},
},
}
checker := crdChecker{client: mgr.GetClient()}
checker := k8sutils.CRDChecker{Client: mgr.GetClient()}
for _, check := range crdChecks {
if !check.Condition {
continue
Expand Down Expand Up @@ -270,44 +266,3 @@ func SetupControllers(mgr manager.Manager, c *Config) (map[string]ControllerDef,

return controllers, nil
}

// crdChecker verifies whether the resource type defined by GVR is supported by the k8s apiserver.
type crdChecker struct {
client client.Client
}

// CRDExists returns true if the apiserver supports the specified group/version/resource.
func (c crdChecker) CRDExists(gvr schema.GroupVersionResource) (bool, error) {
_, err := c.client.RESTMapper().KindFor(gvr)

if meta.IsNoMatchError(err) {
return false, nil
}

if errD := (&discovery.ErrGroupDiscoveryFailed{}); errors.As(err, &errD) {
for _, e := range errD.Groups {

// If this is an API StatusError:
if errS := (&k8serrors.StatusError{}); errors.As(e, &errS) {
switch errS.ErrStatus.Code {
case 404:
// If it's a 404 status code then we're sure that it's just
// a missing CRD. Don't report an error, just false.
return false, nil
default:
return false, fmt.Errorf("unexpected API error status code when looking up CRD (%v): %w", gvr, err)
}
}

// It is a network error.
if errU := (&url.Error{}); errors.As(e, &errU) {
return false, fmt.Errorf("unexpected network error when looking up CRD (%v): %w", gvr, err)
}
}

// Otherwise it's a different error, report a missing CRD.
return false, err
}

return true, nil
}
54 changes: 54 additions & 0 deletions pkg/utils/kubernetes/crd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package kubernetes

import (
"errors"
"fmt"
"net/url"

k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// CRDChecker verifies whether the resource type defined by GVR is supported by the k8s apiserver.
type CRDChecker struct {
Client client.Client
}

// CRDExists returns true if the apiserver supports the specified group/version/resource.
func (c CRDChecker) CRDExists(gvr schema.GroupVersionResource) (bool, error) {
_, err := c.Client.RESTMapper().KindFor(gvr)

if meta.IsNoMatchError(err) {
return false, nil
}

if errD := (&discovery.ErrGroupDiscoveryFailed{}); errors.As(err, &errD) {
for _, e := range errD.Groups {

// If this is an API StatusError:
if errS := (&k8serrors.StatusError{}); errors.As(e, &errS) {
switch errS.ErrStatus.Code {
case 404:
// If it's a 404 status code then we're sure that it's just
// a missing CRD. Don't report an error, just false.
return false, nil
default:
return false, fmt.Errorf("unexpected API error status code when looking up CRD (%v): %w", gvr, err)
}
}

// It is a network error.
if errU := (&url.Error{}); errors.As(e, &errU) {
return false, fmt.Errorf("unexpected network error when looking up CRD (%v): %w", gvr, err)
}
}

// Otherwise it's a different error, report a missing CRD.
return false, err
}

return true, nil
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package manager
package kubernetes

import (
"testing"
Expand Down Expand Up @@ -94,9 +94,7 @@ func TestCRDChecker(t *testing.T) {
WithRESTMapper(tc.restMapper()).
Build()

checker := crdChecker{
client: fakeClient,
}
checker := CRDChecker{Client: fakeClient}
ok, err := checker.CRDExists(tc.CRD)

if tc.expectedErr != nil {
Expand Down

0 comments on commit 649afca

Please sign in to comment.