Apply filters to PublisherController
- Ask the controller package to only call the Sync() method for the specific objects in which this controller is interested
This commit is contained in:
parent
5aebb76146
commit
733f80b7ae
@ -30,6 +30,25 @@ const (
|
||||
configName = "placeholder-name-config"
|
||||
)
|
||||
|
||||
func nameAndNamespaceExactMatchFilterFactory(name, namespace string) controller.FilterFuncs {
|
||||
objMatchesFunc := func(obj metav1.Object) bool {
|
||||
return obj.GetName() == name && obj.GetNamespace() == namespace
|
||||
}
|
||||
return controller.FilterFuncs{
|
||||
AddFunc: objMatchesFunc,
|
||||
UpdateFunc: func(oldObj, newObj metav1.Object) bool {
|
||||
return objMatchesFunc(oldObj) || objMatchesFunc(newObj)
|
||||
},
|
||||
DeleteFunc: objMatchesFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// Same signature as controller.WithInformer().
|
||||
type withInformerOptionFunc func(
|
||||
getter controller.InformerGetter,
|
||||
filter controller.Filter,
|
||||
opt controller.InformerOption) controller.Option
|
||||
|
||||
type publisherController struct {
|
||||
namespace string
|
||||
placeholderClient placeholderclientset.Interface
|
||||
@ -42,6 +61,7 @@ func NewPublisherController(
|
||||
placeholderClient placeholderclientset.Interface,
|
||||
configMapInformer corev1informers.ConfigMapInformer,
|
||||
loginDiscoveryConfigInformer placeholderv1alpha1informers.LoginDiscoveryConfigInformer,
|
||||
withInformer withInformerOptionFunc,
|
||||
) controller.Controller {
|
||||
return controller.New(
|
||||
controller.Config{
|
||||
@ -53,14 +73,14 @@ func NewPublisherController(
|
||||
loginDiscoveryConfigInformer: loginDiscoveryConfigInformer,
|
||||
},
|
||||
},
|
||||
controller.WithInformer(
|
||||
withInformer(
|
||||
configMapInformer,
|
||||
controller.FilterFuncs{}, // TODO fix this and write tests
|
||||
nameAndNamespaceExactMatchFilterFactory(clusterInfoName, clusterInfoNamespace),
|
||||
controller.InformerOption{},
|
||||
),
|
||||
controller.WithInformer(
|
||||
withInformer(
|
||||
loginDiscoveryConfigInformer,
|
||||
controller.FilterFuncs{}, // TODO fix this and write tests
|
||||
nameAndNamespaceExactMatchFilterFactory(configName, namespace),
|
||||
controller.InformerOption{},
|
||||
),
|
||||
)
|
||||
|
@ -29,8 +29,157 @@ import (
|
||||
placeholderinformers "github.com/suzerain-io/placeholder-name-client-go/pkg/generated/informers/externalversions"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
spec.Run(t, "publisher", func(t *testing.T, when spec.G, it spec.S) {
|
||||
type ObservableWithInformerOption struct {
|
||||
InformerToFilterMap map[controller.InformerGetter]controller.Filter
|
||||
}
|
||||
|
||||
func NewObservableWithInformerOption() *ObservableWithInformerOption {
|
||||
return &ObservableWithInformerOption{
|
||||
InformerToFilterMap: make(map[controller.InformerGetter]controller.Filter),
|
||||
}
|
||||
}
|
||||
|
||||
func (owi *ObservableWithInformerOption) WithInformer(
|
||||
getter controller.InformerGetter,
|
||||
filter controller.Filter,
|
||||
opt controller.InformerOption) controller.Option {
|
||||
owi.InformerToFilterMap[getter] = filter
|
||||
return controller.WithInformer(getter, filter, opt)
|
||||
}
|
||||
|
||||
func TestInformerFilters(t *testing.T) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
|
||||
var r *require.Assertions
|
||||
var observableWithInformerOption *ObservableWithInformerOption
|
||||
var configMapInformerFilter controller.Filter
|
||||
var loginDiscoveryConfigInformerFilter controller.Filter
|
||||
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = NewObservableWithInformerOption()
|
||||
configMapInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().ConfigMaps()
|
||||
loginDiscoveryConfigInformer := placeholderinformers.NewSharedInformerFactory(nil, 0).Placeholder().V1alpha1().LoginDiscoveryConfigs()
|
||||
_ = NewPublisherController(
|
||||
installedInNamespace,
|
||||
nil,
|
||||
configMapInformer,
|
||||
loginDiscoveryConfigInformer,
|
||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||
)
|
||||
configMapInformerFilter = observableWithInformerOption.InformerToFilterMap[configMapInformer]
|
||||
loginDiscoveryConfigInformerFilter = observableWithInformerOption.InformerToFilterMap[loginDiscoveryConfigInformer]
|
||||
})
|
||||
|
||||
when("watching ConfigMap objects", func() {
|
||||
var subject controller.Filter
|
||||
var target, wrongNamespace, wrongName, unrelated *corev1.ConfigMap
|
||||
|
||||
it.Before(func() {
|
||||
subject = configMapInformerFilter
|
||||
target = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "kube-public"}}
|
||||
wrongNamespace = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "wrong-namespace"}}
|
||||
wrongName = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "kube-public"}}
|
||||
unrelated = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
||||
})
|
||||
|
||||
when("the target ConfigMap changes", func() {
|
||||
it("returns true to trigger the sync method", func() {
|
||||
r.True(subject.Add(target))
|
||||
r.True(subject.Update(target, unrelated))
|
||||
r.True(subject.Update(unrelated, target))
|
||||
r.True(subject.Delete(target))
|
||||
})
|
||||
})
|
||||
|
||||
when("a ConfigMap from another namespace changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(wrongNamespace))
|
||||
r.False(subject.Update(wrongNamespace, unrelated))
|
||||
r.False(subject.Update(unrelated, wrongNamespace))
|
||||
r.False(subject.Delete(wrongNamespace))
|
||||
})
|
||||
})
|
||||
|
||||
when("a ConfigMap with a different name changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(wrongName))
|
||||
r.False(subject.Update(wrongName, unrelated))
|
||||
r.False(subject.Update(unrelated, wrongName))
|
||||
r.False(subject.Delete(wrongName))
|
||||
})
|
||||
})
|
||||
|
||||
when("a ConfigMap with a different name and a different namespace changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(unrelated))
|
||||
r.False(subject.Update(unrelated, unrelated))
|
||||
r.False(subject.Delete(unrelated))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("watching LoginDiscoveryConfig objects", func() {
|
||||
var subject controller.Filter
|
||||
var target, wrongNamespace, wrongName, unrelated *placeholderv1alpha1.LoginDiscoveryConfig
|
||||
|
||||
it.Before(func() {
|
||||
subject = loginDiscoveryConfigInformerFilter
|
||||
target = &placeholderv1alpha1.LoginDiscoveryConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "placeholder-name-config", Namespace: installedInNamespace},
|
||||
}
|
||||
wrongNamespace = &placeholderv1alpha1.LoginDiscoveryConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "placeholder-name-config", Namespace: "wrong-namespace"},
|
||||
}
|
||||
wrongName = &placeholderv1alpha1.LoginDiscoveryConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace},
|
||||
}
|
||||
unrelated = &placeholderv1alpha1.LoginDiscoveryConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"},
|
||||
}
|
||||
})
|
||||
|
||||
when("the target LoginDiscoveryConfig changes", func() {
|
||||
it("returns true to trigger the sync method", func() {
|
||||
r.True(subject.Add(target))
|
||||
r.True(subject.Update(target, unrelated))
|
||||
r.True(subject.Update(unrelated, target))
|
||||
r.True(subject.Delete(target))
|
||||
})
|
||||
})
|
||||
|
||||
when("a LoginDiscoveryConfig from another namespace changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(wrongNamespace))
|
||||
r.False(subject.Update(wrongNamespace, unrelated))
|
||||
r.False(subject.Update(unrelated, wrongNamespace))
|
||||
r.False(subject.Delete(wrongNamespace))
|
||||
})
|
||||
})
|
||||
|
||||
when("a LoginDiscoveryConfig with a different name changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(wrongName))
|
||||
r.False(subject.Update(wrongName, unrelated))
|
||||
r.False(subject.Update(unrelated, wrongName))
|
||||
r.False(subject.Delete(wrongName))
|
||||
})
|
||||
})
|
||||
|
||||
when("a LoginDiscoveryConfig with a different name and a different namespace changes", func() {
|
||||
it("returns false to avoid triggering the sync method", func() {
|
||||
r.False(subject.Add(unrelated))
|
||||
r.False(subject.Update(unrelated, unrelated))
|
||||
r.False(subject.Delete(unrelated))
|
||||
})
|
||||
})
|
||||
})
|
||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
|
||||
var r *require.Assertions
|
||||
@ -89,6 +238,7 @@ func TestRun(t *testing.T) {
|
||||
placeholderAPIClient,
|
||||
kubeInformers.Core().V1().ConfigMaps(),
|
||||
placeholderInformers.Placeholder().V1alpha1().LoginDiscoveryConfigs(),
|
||||
controller.WithInformer,
|
||||
)
|
||||
|
||||
syncContext = &controller.Context{
|
||||
@ -131,7 +281,7 @@ func TestRun(t *testing.T) {
|
||||
})
|
||||
|
||||
when("the LoginDiscoveryConfig does not already exist", func() {
|
||||
it.Focus("creates a LoginDiscoveryConfig", func() {
|
||||
it("creates a LoginDiscoveryConfig", func() {
|
||||
startInformersAndController()
|
||||
err := controller.TestSync(t, subject, *syncContext)
|
||||
r.NoError(err)
|
||||
@ -287,23 +437,5 @@ func TestRun(t *testing.T) {
|
||||
r.Empty(placeholderAPIClient.Actions())
|
||||
})
|
||||
})
|
||||
|
||||
when("getting the cluster-info ConfigMap in the kube-public namespace fails", func() {
|
||||
it.Before(func() {
|
||||
kubeInformerClient.PrependReactor(
|
||||
"get",
|
||||
"configmaps",
|
||||
func(_ coretesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, errors.New("get failed")
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it("returns an error", func() {
|
||||
startInformersAndController()
|
||||
err := controller.TestSync(t, subject, *syncContext)
|
||||
r.EqualError(err, "failed to get cluster-info configmap: get failed")
|
||||
})
|
||||
})
|
||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user