Disable controllers using a command-line flag (#2339)

* Disable controllers using a flag

This patch allows disabling controllers when using a new `Main` function
called `MainNamed` which takes a list of `NamedControllerConstructor`.

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>

* Apply reviews

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>

* Add comments, split filter and conversion

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>

* Allocate len(ctors)

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>

* to disable -> disabling

Signed-off-by: Pierangelo Di Pilato <pdipilat@redhat.com>
This commit is contained in:
Pierangelo Di Pilato 2021-11-16 22:30:53 +01:00 committed by GitHub
parent 517ef0292b
commit d82be484e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 120 additions and 0 deletions

View File

@ -103,6 +103,14 @@ type DynamicInterface interface {
type ControllerConstructor func(context.Context, configmap.Watcher) *controller.Impl
// NamedControllerConstructor is a ControllerConstructor with an associated name.
type NamedControllerConstructor struct {
// Name is the name associated with the controller returned by ControllerConstructor.
Name string
// ControllerConstructor is a constructor for a controller.
ControllerConstructor ControllerConstructor
}
var (
// Check that impl implements Interface
_ Interface = (*impl)(nil)

View File

@ -26,6 +26,8 @@ import (
"os"
"time"
"github.com/spf13/pflag"
"go.uber.org/automaxprocs/maxprocs" // automatically set GOMAXPROCS based on cgroups
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
@ -34,6 +36,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/rest"
@ -111,6 +114,43 @@ var (
WebhookMainWithConfig = MainWithConfig
)
// MainNamed runs the generic main flow for controllers and webhooks.
//
// In addition to the MainWithConfig flow, it defines a `disabled-controllers` flag that allows disabling controllers
// by name.
func MainNamed(ctx context.Context, component string, ctors ...injection.NamedControllerConstructor) {
disabledControllers := pflag.StringSlice("disable-controllers", []string{}, "Comma-separated list of disabled controllers.")
// HACK: This parses flags, so the above should be set once this runs.
cfg := injection.ParseAndGetRESTConfigOrDie()
enabledCtors := enabledControllers(*disabledControllers, ctors)
MainWithConfig(ctx, component, cfg, toControllerConstructors(enabledCtors)...)
}
func enabledControllers(disabledControllers []string, ctors []injection.NamedControllerConstructor) []injection.NamedControllerConstructor {
disabledControllersSet := sets.NewString(disabledControllers...)
activeCtors := make([]injection.NamedControllerConstructor, 0, len(ctors))
for _, ctor := range ctors {
if disabledControllersSet.Has(ctor.Name) {
log.Printf("Disabling controller %s", ctor.Name)
continue
}
activeCtors = append(activeCtors, ctor)
}
return activeCtors
}
func toControllerConstructors(namedCtors []injection.NamedControllerConstructor) []injection.ControllerConstructor {
ctors := make([]injection.ControllerConstructor, 0, len(namedCtors))
for _, ctor := range namedCtors {
ctors = append(ctors, ctor.ControllerConstructor)
}
return ctors
}
// MainWithContext runs the generic main flow for controllers and
// webhooks. Use MainWithContext if you do not need to serve webhooks.
func MainWithContext(ctx context.Context, component string, ctors ...injection.ControllerConstructor) {

View File

@ -0,0 +1,72 @@
/*
Copyright 2021 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package sharedmain
import (
"testing"
"github.com/google/go-cmp/cmp"
"knative.dev/pkg/injection"
)
func TestEnabledControllers(t *testing.T) {
tests := []struct {
name string
disabledControllers []string
ctors []injection.NamedControllerConstructor
wantNames []string
}{
{
name: "zero",
disabledControllers: []string{"foo"},
ctors: []injection.NamedControllerConstructor{{Name: "bar"}},
wantNames: []string{"bar"},
},
{
name: "one",
disabledControllers: []string{"foo"},
ctors: []injection.NamedControllerConstructor{{Name: "foo"}},
wantNames: []string{},
},
{
name: "two",
disabledControllers: []string{"foo"},
ctors: []injection.NamedControllerConstructor{
{Name: "foo"},
{Name: "bar"},
},
wantNames: []string{"bar"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := enabledControllers(tt.disabledControllers, tt.ctors)
if diff := cmp.Diff(tt.wantNames, namesOf(got)); diff != "" {
t.Error("(-want, +got)", diff)
}
})
}
}
func namesOf(ctors []injection.NamedControllerConstructor) []string {
names := make([]string, 0, len(ctors))
for _, x := range ctors {
names = append(names, x.Name)
}
return names
}