mirror of https://github.com/knative/pkg.git
Add the ability to scope informers to a namespace with injection. (#626)
This commit is contained in:
parent
8cae700d29
commit
524f6c5bb2
|
|
@ -64,11 +64,15 @@ func (g *factoryGenerator) GenerateType(c *generator.Context, t *types.Type, w i
|
|||
klog.V(5).Infof("processing type %v", t)
|
||||
|
||||
m := map[string]interface{}{
|
||||
"cachingClientGet": c.Universe.Type(types.Name{Package: g.cachingClientSetPackage, Name: "Get"}),
|
||||
"informersNewSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactory"}),
|
||||
"informersSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerFactory"}),
|
||||
"injectionRegisterInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterInformerFactory"}),
|
||||
"controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}),
|
||||
"cachingClientGet": c.Universe.Type(types.Name{Package: g.cachingClientSetPackage, Name: "Get"}),
|
||||
"informersNewSharedInformerFactoryWithOptions": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactoryWithOptions"}),
|
||||
"informersSharedInformerOption": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerOption"}),
|
||||
"informersWithNamespace": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "WithNamespace"}),
|
||||
"informersSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerFactory"}),
|
||||
"injectionRegisterInformerFactory": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "Default.RegisterInformerFactory"}),
|
||||
"injectionHasNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "HasNamespaceScope"}),
|
||||
"injectionGetNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "GetNamespaceScope"}),
|
||||
"controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}),
|
||||
"loggingFromContext": c.Universe.Function(types.Name{
|
||||
Package: "knative.dev/pkg/logging",
|
||||
Name: "FromContext",
|
||||
|
|
@ -90,8 +94,12 @@ type Key struct{}
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
c := {{.cachingClientGet|raw}}(ctx)
|
||||
opts := make([]{{.informersSharedInformerOption|raw}}, 0, 1)
|
||||
if {{.injectionHasNamespace|raw}}(ctx) {
|
||||
opts = append(opts, {{.informersWithNamespace|raw}}({{.injectionGetNamespace|raw}}(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, Key{},
|
||||
{{.informersNewSharedInformerFactory|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx)))
|
||||
{{.informersNewSharedInformerFactoryWithOptions|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx), opts...))
|
||||
}
|
||||
|
||||
// Get extracts the InformerFactory from the context.
|
||||
|
|
|
|||
|
|
@ -66,14 +66,18 @@ func (g *fakeFactoryGenerator) GenerateType(c *generator.Context, t *types.Type,
|
|||
klog.V(5).Infof("processing type %v", t)
|
||||
|
||||
m := map[string]interface{}{
|
||||
"factoryKey": c.Universe.Type(types.Name{Package: g.factoryInjectionPkg, Name: "Key"}),
|
||||
"factoryGet": c.Universe.Function(types.Name{Package: g.factoryInjectionPkg, Name: "Get"}),
|
||||
"clientGet": c.Universe.Function(types.Name{Package: g.fakeClientInjectionPkg, Name: "Get"}),
|
||||
"informersNewSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactory"}),
|
||||
"factoryKey": c.Universe.Type(types.Name{Package: g.factoryInjectionPkg, Name: "Key"}),
|
||||
"factoryGet": c.Universe.Function(types.Name{Package: g.factoryInjectionPkg, Name: "Get"}),
|
||||
"clientGet": c.Universe.Function(types.Name{Package: g.fakeClientInjectionPkg, Name: "Get"}),
|
||||
"informersNewSharedInformerFactoryWithOptions": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactoryWithOptions"}),
|
||||
"informersSharedInformerOption": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerOption"}),
|
||||
"informersWithNamespace": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "WithNamespace"}),
|
||||
"injectionRegisterInformerFactory": c.Universe.Function(types.Name{
|
||||
Package: "knative.dev/pkg/injection",
|
||||
Name: "Fake.RegisterInformerFactory",
|
||||
}),
|
||||
"injectionHasNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "HasNamespaceScope"}),
|
||||
"injectionGetNamespace": c.Universe.Type(types.Name{Package: "knative.dev/pkg/injection", Name: "GetNamespaceScope"}),
|
||||
"controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "knative.dev/pkg/controller", Name: "GetResyncPeriod"}),
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +95,11 @@ func init() {
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
c := {{.clientGet|raw}}(ctx)
|
||||
opts := make([]{{.informersSharedInformerOption|raw}}, 0, 1)
|
||||
if {{.injectionHasNamespace|raw}}(ctx) {
|
||||
opts = append(opts, {{.informersWithNamespace|raw}}({{.injectionGetNamespace|raw}}(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, {{.factoryKey|raw}}{},
|
||||
{{.informersNewSharedInformerFactory|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx)))
|
||||
{{.informersNewSharedInformerFactoryWithOptions|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx), opts...))
|
||||
}
|
||||
`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2019 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 injection
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// nsKey is the key that namespaces are associated with on
|
||||
// contexts returned by WithNamespaceScope.
|
||||
type nsKey struct{}
|
||||
|
||||
// WithNamespaceScope associates a namespace scoping with the
|
||||
// provided context, which will scope the informers produced
|
||||
// by the downstream informer factories.
|
||||
func WithNamespaceScope(ctx context.Context, namespace string) context.Context {
|
||||
return context.WithValue(ctx, nsKey{}, namespace)
|
||||
}
|
||||
|
||||
// HasNamespaceScope determines whether the provided context has
|
||||
// been scoped to a particular namespace.
|
||||
func HasNamespaceScope(ctx context.Context) bool {
|
||||
return GetNamespaceScope(ctx) != ""
|
||||
}
|
||||
|
||||
// GetNamespaceScope accesses the namespace associated with the
|
||||
// provided context. This should be called when the injection
|
||||
// logic is setting up shared informer factories.
|
||||
func GetNamespaceScope(ctx context.Context) string {
|
||||
value := ctx.Value(nsKey{})
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
return value.(string)
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 2019 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 injection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetBaseline(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
if HasNamespaceScope(ctx) {
|
||||
t.Error("HasNamespaceScope() = true, wanted false")
|
||||
}
|
||||
|
||||
want := "this-is-the-best-ns-evar"
|
||||
ctx = WithNamespaceScope(ctx, want)
|
||||
|
||||
if !HasNamespaceScope(ctx) {
|
||||
t.Error("HasNamespaceScope() = false, wanted true")
|
||||
}
|
||||
|
||||
if got := GetNamespaceScope(ctx); got != want {
|
||||
t.Errorf("GetNamespaceScope() = %v, wanted %v", got, want)
|
||||
}
|
||||
}
|
||||
|
|
@ -65,4 +65,41 @@ limitations under the License.
|
|||
// dave.NewController,
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// If you want to adapt the above to run the controller within a single
|
||||
// namespace, you can instead do something like:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// // The set of controllers this controller process runs.
|
||||
// // Linking these will register their transitive dependencies, after
|
||||
// // which the shared main can set up the rest.
|
||||
// "github.com/knative/foo/pkg/reconciler/matt"
|
||||
// "github.com/knative/foo/pkg/reconciler/scott"
|
||||
// "github.com/knative/foo/pkg/reconciler/ville"
|
||||
// "github.com/knative/foo/pkg/reconciler/dave"
|
||||
//
|
||||
// // This defines the shared main for injected controllers.
|
||||
// "knative.dev/pkg/injection/sharedmain"
|
||||
//
|
||||
// // These are used to set up the context.
|
||||
// "knative.dev/pkg/injection"
|
||||
// "knative.dev/pkg/signals"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// // Scope the shared informer factories to the provided namespace.
|
||||
// ctx := injection.WithNamespace(signals.NewContext(), "the-namespace")
|
||||
//
|
||||
// // Use our initial context when setting up the controllers.
|
||||
// sharedmain.MainWithContext(ctx, "mycomponent",
|
||||
// // We pass in the list of controllers to construct, and that's it!
|
||||
// // If we forget to add this, go will complain about the unused import.
|
||||
// matt.NewController,
|
||||
// scott.NewController,
|
||||
// ville.NewController,
|
||||
// dave.NewController,
|
||||
// )
|
||||
// }
|
||||
package injection
|
||||
|
|
|
|||
|
|
@ -38,8 +38,12 @@ type Key struct{}
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
axc := apiextclient.Get(ctx)
|
||||
opts := make([]informers.SharedInformerOption, 0, 1)
|
||||
if injection.HasNamespaceScope(ctx) {
|
||||
opts = append(opts, informers.WithNamespace(injection.GetNamespaceScope(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, Key{},
|
||||
informers.NewSharedInformerFactory(axc, controller.GetResyncPeriod(ctx)))
|
||||
informers.NewSharedInformerFactoryWithOptions(axc, controller.GetResyncPeriod(ctx), opts...))
|
||||
}
|
||||
|
||||
// Get extracts the Kubernetes Api Extensions InformerFactory from the context.
|
||||
|
|
|
|||
|
|
@ -64,3 +64,28 @@ func TestRegistration(t *testing.T) {
|
|||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrationWithNamespace(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx = injection.WithNamespaceScope(ctx, "secret-sauce")
|
||||
|
||||
// Check how many informer factories have registered.
|
||||
inffs := injection.Default.GetInformerFactories()
|
||||
if want, got := 1, len(inffs); want != got {
|
||||
t.Errorf("GetInformerFactories() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Setup the informers.
|
||||
var infs []controller.Informer
|
||||
ctx, infs = injection.Default.SetupInformers(ctx, &rest.Config{})
|
||||
|
||||
// We should see that a single informer was set up.
|
||||
if want, got := 0, len(infs); want != got {
|
||||
t.Errorf("SetupInformers() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Get our informer from the context.
|
||||
if inf := Get(ctx); inf == nil {
|
||||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ func init() {
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
kc := fake.Get(ctx)
|
||||
opts := make([]informers.SharedInformerOption, 0, 1)
|
||||
if injection.HasNamespaceScope(ctx) {
|
||||
opts = append(opts, informers.WithNamespace(injection.GetNamespaceScope(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, factory.Key{},
|
||||
informers.NewSharedInformerFactory(kc, controller.GetResyncPeriod(ctx)))
|
||||
informers.NewSharedInformerFactoryWithOptions(kc, controller.GetResyncPeriod(ctx), opts...))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,3 +64,29 @@ func TestRegistration(t *testing.T) {
|
|||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrationWithNamespace(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
ctx = injection.WithNamespaceScope(ctx, "fake-news")
|
||||
|
||||
// Check how many informer factories have registered.
|
||||
inffs := injection.Fake.GetInformerFactories()
|
||||
if want, got := 1, len(inffs); want != got {
|
||||
t.Errorf("GetInformerFactories() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Setup the informers.
|
||||
var infs []controller.Informer
|
||||
ctx, infs = injection.Fake.SetupInformers(ctx, &rest.Config{})
|
||||
|
||||
// We should see that a single informer was set up.
|
||||
if want, got := 0, len(infs); want != got {
|
||||
t.Errorf("SetupInformers() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Get our informer from the context.
|
||||
if inf := Get(ctx); inf == nil {
|
||||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,12 @@ type Key struct{}
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
kc := kubeclient.Get(ctx)
|
||||
opts := make([]informers.SharedInformerOption, 0, 1)
|
||||
if injection.HasNamespaceScope(ctx) {
|
||||
opts = append(opts, informers.WithNamespace(injection.GetNamespaceScope(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, Key{},
|
||||
informers.NewSharedInformerFactory(kc, controller.GetResyncPeriod(ctx)))
|
||||
informers.NewSharedInformerFactoryWithOptions(kc, controller.GetResyncPeriod(ctx), opts...))
|
||||
}
|
||||
|
||||
// Get extracts the Kubernetes InformerFactory from the context.
|
||||
|
|
|
|||
|
|
@ -64,3 +64,29 @@ func TestRegistration(t *testing.T) {
|
|||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrationWithNamespace(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
ctx = injection.WithNamespaceScope(ctx, "secret-sauce")
|
||||
|
||||
// Check how many informer factories have registered.
|
||||
inffs := injection.Default.GetInformerFactories()
|
||||
if want, got := 1, len(inffs); want != got {
|
||||
t.Errorf("GetInformerFactories() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Setup the informers.
|
||||
var infs []controller.Informer
|
||||
ctx, infs = injection.Default.SetupInformers(ctx, &rest.Config{})
|
||||
|
||||
// We should see that a single informer was set up.
|
||||
if want, got := 0, len(infs); want != got {
|
||||
t.Errorf("SetupInformers() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Get our informer from the context.
|
||||
if inf := Get(ctx); inf == nil {
|
||||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ func init() {
|
|||
|
||||
func withInformerFactory(ctx context.Context) context.Context {
|
||||
kc := fake.Get(ctx)
|
||||
opts := make([]informers.SharedInformerOption, 0, 1)
|
||||
if injection.HasNamespaceScope(ctx) {
|
||||
opts = append(opts, informers.WithNamespace(injection.GetNamespaceScope(ctx)))
|
||||
}
|
||||
return context.WithValue(ctx, factory.Key{},
|
||||
informers.NewSharedInformerFactory(kc, controller.GetResyncPeriod(ctx)))
|
||||
informers.NewSharedInformerFactoryWithOptions(kc, controller.GetResyncPeriod(ctx), opts...))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,3 +64,29 @@ func TestRegistration(t *testing.T) {
|
|||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrationWithNamespace(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
ctx = injection.WithNamespaceScope(ctx, "fake-news")
|
||||
|
||||
// Check how many informer factories have registered.
|
||||
inffs := injection.Fake.GetInformerFactories()
|
||||
if want, got := 1, len(inffs); want != got {
|
||||
t.Errorf("GetInformerFactories() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Setup the informers.
|
||||
var infs []controller.Informer
|
||||
ctx, infs = injection.Fake.SetupInformers(ctx, &rest.Config{})
|
||||
|
||||
// We should see that a single informer was set up.
|
||||
if want, got := 0, len(infs); want != got {
|
||||
t.Errorf("SetupInformers() = %d, wanted %d", want, got)
|
||||
}
|
||||
|
||||
// Get our informer from the context.
|
||||
if inf := Get(ctx); inf == nil {
|
||||
t.Error("Get() = nil, wanted non-nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue