Skip to content

incorrect check for duplicate controller names #2937

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

Closed
nicks opened this issue Sep 2, 2024 · 6 comments
Closed

incorrect check for duplicate controller names #2937

nicks opened this issue Sep 2, 2024 · 6 comments

Comments

@nicks
Copy link

nicks commented Sep 2, 2024

Repro steps

Add the following test:

package scratch

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"k8s.io/client-go/rest"

	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

var rec = reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
	return reconcile.Result{}, nil
})
var cfg = &rest.Config{}

func TestManager(t *testing.T) {
	m, err := manager.New(cfg, manager.Options{})
	assert.NoError(t, err)

	_, err = controller.New("c1", m, controller.Options{Reconciler: rec})
	assert.NoError(t, err)
}

func TestManager2(t *testing.T) {
	m, err := manager.New(cfg, manager.Options{})
	assert.NoError(t, err)

	_, err = controller.New("c1", m, controller.Options{Reconciler: rec})
	assert.NoError(t, err)
}

Expected result
Tests pass

Actual result
Tests fail

controller with name c1 already exists. Controller names must be unique to avoid multiple controllers reporting to the same metric

Additional info

controller-runtime seems to have implemented a uniqueness check based on global state with no way to reset the global state for tests :(

@bigkevmcd
Copy link
Contributor

You can disable the name verification (which prevents the name being added to the set of previously seen names).

This PR landed the change #2918

_, err = controller.New("c1", m, controller.Options{Reconciler: rec, SkipNameValidation: ptr.To(true)})

@AndreiBarbuOz
Copy link

You can disable the name verification (which prevents the name being added to the set of previously seen names).

This is not a particularly appealing option. I'd rather not mix my test code (where the controllers need to skip validation) and production code (where the validation should be executed)

If you have a project which follows the Kubebuilder book, you're very likely to use the builder pattern, and not have an easy way of injecting configuration to all controllers

@alvaroaleman
Copy link
Member

f you have a project which follows the Kubebuilder book, you're very likely to use the builder pattern, and not have an easy way of injecting configuration to all controllers

It is also an option on the manager, setting it there will disable it for all controllers managed by this manager.

@AndreiBarbuOz
Copy link

AndreiBarbuOz commented Sep 8, 2024

@alvaroaleman , can you indicate where that option resides?

i assumed it would be part of this structure, but it is not the case:

// Options are the arguments for creating a new Manager.
type Options struct {
// Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources.
// Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
// to pass your own scheme in. See the documentation in pkg/scheme for more information.
//
// If set, the Scheme will be used to create the default Client and Cache.
Scheme *runtime.Scheme

LE: the configuration is going through the config package actually

// Controller contains global configuration options for controllers
// registered within this manager.
// +optional
Controller config.Controller

@alvaroaleman
Copy link
Member

managerOpts.Controller.SkipNameValidation, yes.

RamLavi added a commit to RamLavi/kube-admission-webhook that referenced this issue Jan 9, 2025
- Also bumped controller-runtime to v0.19.3
  - Updated Watch function and predicates.
- unit tests: Added SkipNameValidation:true when creating new
controller-runtime manager to avoid "unique controller name" check [0]
- Fixed lint issues due to go bump:
  - deprecated function PollImmediate

[0] kubernetes-sigs/controller-runtime#2937

Signed-off-by: Ram Lavi <[email protected]>
RamLavi added a commit to RamLavi/kube-admission-webhook that referenced this issue Jan 12, 2025
- Also bumped controller-runtime to v0.19.3
  - Updated Watch function and predicates.
- unit tests: Added SkipNameValidation:true when creating new
controller-runtime manager to avoid "unique controller name" check [0]
- Fixed lint issues due to go bump:
  - deprecated function PollImmediate

[0] kubernetes-sigs/controller-runtime#2937

Signed-off-by: Ram Lavi <[email protected]>
qinqon pushed a commit to qinqon/kube-admission-webhook that referenced this issue Jan 15, 2025
- Also bumped controller-runtime to v0.19.3
  - Updated Watch function and predicates.
- unit tests: Added SkipNameValidation:true when creating new
controller-runtime manager to avoid "unique controller name" check [0]
- Fixed lint issues due to go bump:
  - deprecated function PollImmediate

[0] kubernetes-sigs/controller-runtime#2937

Signed-off-by: Ram Lavi <[email protected]>
@shatil
Copy link

shatil commented Mar 6, 2025

You can disable the name verification (which prevents the name being added to the set of previously seen names).

This is not a particularly appealing option. I'd rather not mix my test code (where the controllers need to skip validation) and production code (where the validation should be executed)

@AndreiBarbuOz, I encountered the same error when running multiple controllers that reconcile the same object.

controller with name $name already exists. Controller names must be unique to avoid multiple controllers reporting to the same metric

My workaround was to assign the controllers a unique name:

ctrl.NewControllerManagedBy(mgr).
	Named(r.Name()). // this assigns the controller a unique name
	For(&MyType{}).
	Complete(r)

Can you use the test name as your controller name to avoid the conflict?

-	_, err = controller.New("c1", m, controller.Options{Reconciler: rec})
+	_, err = controller.New(t.Name(), m, controller.Options{Reconciler: rec})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants