Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport to release/3.4.x] fix(manager): Run AddToScheme only once in scheme.Get #7116

Merged
merged 1 commit into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ Adding a new version? You'll need three changes:
- [0.0.5](#005)
- [0.0.4 and prior](#004-and-prior)

## Unreleased

### Fixed

- `AddToScheme` is only run in the initialization of scheme of the manager but
not called in `scheme.Get` to reduce the CPU usage.
[#7105](https://github.com/Kong/kubernetes-ingress-controller/pull/7105)

## [3.4.1]

> Release date: 2025-01-02
Expand Down
2 changes: 1 addition & 1 deletion internal/admission/validation/gateway/httproute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ func TestValidateHTTPRoute(t *testing.T) {
t.Run(tt.msg, func(t *testing.T) {
fakeClient := fakeclient.
NewClientBuilder().
WithScheme(lo.Must(scheme.Get())).
WithScheme(scheme.Get()).
WithObjects(tt.cachedObjects...).
Build()

Expand Down
2 changes: 1 addition & 1 deletion internal/admission/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,7 @@ func TestValidator_ValidateIngress(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
storer := lo.Must(store.NewFakeStore(tc.storerObjects))
validator := KongHTTPValidator{
ManagerClient: fake.NewClientBuilder().WithScheme(lo.Must(managerscheme.Get())).WithObjects(tc.clientObjects...).Build(),
ManagerClient: fake.NewClientBuilder().WithScheme(managerscheme.Get()).WithObjects(tc.clientObjects...).Build(),
Storer: storer,
AdminAPIServicesProvider: fakeServicesProvider{
routeSvc: &fakeRouteSvc{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ func TestEnforceKongUpstreamPolicyStatus(t *testing.T) {
tc.inputObjects = append(tc.inputObjects, &tc.kongUpstreamPolicy)
fakeClient := fakectrlruntimeclient.
NewClientBuilder().
WithScheme(lo.Must(scheme.Get())).
WithScheme(scheme.Get()).
WithObjects(tc.inputObjects...).
WithStatusSubresource(tc.inputObjects...).
WithIndex(&corev1.Service{}, upstreamPolicyIndexKey, indexServicesOnUpstreamPolicyAnnotation).
Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/gateway/route_predicate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func TestIsRouteAttachedToReconciledGateway(t *testing.T) {
}

for _, tc := range httpRouteTestCases {
cl := fakeclient.NewClientBuilder().WithScheme(lo.Must(scheme.Get())).WithObjects(tc.objects...).Build()
cl := fakeclient.NewClientBuilder().WithScheme(scheme.Get()).WithObjects(tc.objects...).Build()
t.Run(tc.name, func(t *testing.T) {
logger := logr.Discard()
result := IsRouteAttachedToReconciledGateway[*gatewayapi.HTTPRoute](cl, logger, tc.gatewayNN, tc.route)
Expand Down
6 changes: 1 addition & 5 deletions internal/controllers/reference/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ func objectKeyFunc(obj client.Object) (string, error) {
if !ok {
return "", fmt.Errorf("could not convert %s/%s back to client Object", obj.GetNamespace(), obj.GetName())
}
s, err := scheme.Get()
if err != nil {
return "", fmt.Errorf("could not get scheme for %s/%s metadata: %w", obj.GetNamespace(), obj.GetName(), err)
}
err = util.PopulateTypeMeta(o, s)
err := util.PopulateTypeMeta(o, scheme.Get())
if err != nil {
return "", fmt.Errorf("could not populate %s/%s metadata: %w", obj.GetNamespace(), obj.GetName(), err)
}
Expand Down
4 changes: 1 addition & 3 deletions internal/dataplane/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1096,9 +1096,7 @@ func TestServiceClientCertificate(t *testing.T) {
},
}
for _, service := range services {
scheme, err := scheme.Get()
require.NoError(t, err)
err = util.PopulateTypeMeta(service, scheme)
err := util.PopulateTypeMeta(service, scheme.Get())
require.NoError(t, err)
}
store, err := store.NewFakeStore(store.FakeObjects{
Expand Down
5 changes: 1 addition & 4 deletions internal/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,7 @@ func Run(
}

setupLog.Info("Configuring and building the controller manager")
managerOpts, err := setupManagerOptions(ctx, setupLog, c, dbMode)
if err != nil {
return fmt.Errorf("unable to setup manager options: %w", err)
}
managerOpts := setupManagerOptions(ctx, setupLog, c, dbMode)

mgr, err := ctrl.NewManager(kubeconfig, managerOpts)
if err != nil {
Expand Down
64 changes: 23 additions & 41 deletions internal/manager/scheme/scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package scheme
import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
Expand All @@ -15,46 +16,27 @@ import (
incubatorv1alpha1 "github.com/kong/kubernetes-configuration/api/incubator/v1alpha1"
)

var kicScheme *runtime.Scheme = initScheme()

func initScheme() *runtime.Scheme {
s := runtime.NewScheme()
utilruntime.Must(apiextensionsv1.AddToScheme(s))
utilruntime.Must(clientgoscheme.AddToScheme(s))

utilruntime.Must(kongv1.AddToScheme(s))
utilruntime.Must(kongv1alpha1.AddToScheme(s))
utilruntime.Must(kongv1beta1.AddToScheme(s))
utilruntime.Must(incubatorv1alpha1.AddToScheme(s))

utilruntime.Must(gatewayv1.Install(s))
utilruntime.Must(gatewayv1beta1.Install(s))
utilruntime.Must(gatewayv1alpha2.Install(s))
utilruntime.Must(gatewayv1alpha3.Install(s))

return s
}

// Get returns a scheme aware of all types the manager can interact with.
func Get() (*runtime.Scheme, error) {
scheme := runtime.NewScheme()

if err := apiextensionsv1.AddToScheme(scheme); err != nil {
return nil, err
}

if err := clientgoscheme.AddToScheme(scheme); err != nil {
return nil, err
}

if err := kongv1.AddToScheme(scheme); err != nil {
return nil, err
}
if err := kongv1alpha1.AddToScheme(scheme); err != nil {
return nil, err
}
if err := kongv1beta1.AddToScheme(scheme); err != nil {
return nil, err
}
if err := incubatorv1alpha1.AddToScheme(scheme); err != nil {
return nil, err
}

if err := gatewayv1alpha2.Install(scheme); err != nil {
return nil, err
}

if err := gatewayv1alpha3.Install(scheme); err != nil {
return nil, err
}

if err := gatewayv1beta1.Install(scheme); err != nil {
return nil, err
}

if err := gatewayv1.Install(scheme); err != nil {
return nil, err
}

return scheme, nil
func Get() *runtime.Scheme {
return kicScheme
}
10 changes: 3 additions & 7 deletions internal/manager/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,8 @@ func SetupLoggers(c *Config, output io.Writer) (logr.Logger, error) {
return logger, nil
}

func setupManagerOptions(ctx context.Context, logger logr.Logger, c *Config, dbmode dpconf.DBMode) (ctrl.Options, error) {
func setupManagerOptions(ctx context.Context, logger logr.Logger, c *Config, dbmode dpconf.DBMode) ctrl.Options {
logger.Info("Building the manager runtime scheme and loading apis into the scheme")
scheme, err := scheme.Get()
if err != nil {
return ctrl.Options{}, err
}

// configure the general manager options
managerOpts := ctrl.Options{
Expand All @@ -85,7 +81,7 @@ func setupManagerOptions(ctx context.Context, logger logr.Logger, c *Config, dbm
SkipNameValidation: lo.ToPtr(true),
},
GracefulShutdownTimeout: c.GracefulShutdownTimeout,
Scheme: scheme,
Scheme: scheme.Get(),
Metrics: metricsserver.Options{
BindAddress: c.MetricsAddr,
},
Expand Down Expand Up @@ -130,7 +126,7 @@ func setupManagerOptions(ctx context.Context, logger logr.Logger, c *Config, dbm
managerOpts.LeaderElectionNamespace = c.LeaderElectionNamespace
}

return managerOpts, nil
return managerOpts
}

const (
Expand Down
6 changes: 1 addition & 5 deletions internal/store/cache_stores.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ import (
// NewCacheStoresFromObjYAML provides a new CacheStores object given any number of byte arrays containing
// YAML Kubernetes objects. An error is returned if any provided YAML was not a valid Kubernetes object.
func NewCacheStoresFromObjYAML(objs ...[]byte) (c CacheStores, err error) {
s, err := scheme.Get()
if err != nil {
return c, err
}
kobjs := make([]runtime.Object, 0, len(objs))
sr := serializer.NewYAMLSerializer(
yamlserializer.DefaultMetaFactory,
Expand All @@ -30,7 +26,7 @@ func NewCacheStoresFromObjYAML(objs ...[]byte) (c CacheStores, err error) {
if err = decodeErr; err != nil {
return
}
if err := util.PopulateTypeMeta(kobj, s); err != nil {
if err := util.PopulateTypeMeta(kobj, scheme.Get()); err != nil {
return c, err
}
kobjs = append(kobjs, kobj)
Expand Down
3 changes: 1 addition & 2 deletions internal/util/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package util
import (
"testing"

"github.com/samber/lo"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -28,7 +27,7 @@ func TestPopulateTypeMeta(t *testing.T) {

require.Empty(t, credential.GetObjectKind().GroupVersionKind().Kind)

err := PopulateTypeMeta(credential, lo.Must(scheme.Get()))
err := PopulateTypeMeta(credential, scheme.Get())

require.NoError(t, err)
require.NotEmpty(t, credential.GetObjectKind().GroupVersionKind().Kind)
Expand Down
4 changes: 1 addition & 3 deletions test/helpers/k8s_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import (

// WithTypeMeta adds type meta to the given object based on its Go type.
func WithTypeMeta[T runtime.Object](t *testing.T, obj T) T {
s, err := scheme.Get()
require.NoError(t, err)
err = util.PopulateTypeMeta(obj, s)
err := util.PopulateTypeMeta(obj, scheme.Get())
require.NoError(t, err)
return obj
}
3 changes: 1 addition & 2 deletions test/mocks/events_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ func (r *EventRecorder) writeEvent(o runtime.Object, eventtype, reason, messageF
r.l.Lock()
defer r.l.Unlock()

s, _ := scheme.Get()
_ = util.PopulateTypeMeta(o, s)
_ = util.PopulateTypeMeta(o, scheme.Get())
fmtString := fmt.Sprintf("%s: %s %s %s", o.GetObjectKind().GroupVersionKind().Kind, eventtype, reason, messageFmt)
r.events = append(r.events, fmt.Sprintf(fmtString, args...))
}