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"
|
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 {
|
type publisherController struct {
|
||||||
namespace string
|
namespace string
|
||||||
placeholderClient placeholderclientset.Interface
|
placeholderClient placeholderclientset.Interface
|
||||||
@ -42,6 +61,7 @@ func NewPublisherController(
|
|||||||
placeholderClient placeholderclientset.Interface,
|
placeholderClient placeholderclientset.Interface,
|
||||||
configMapInformer corev1informers.ConfigMapInformer,
|
configMapInformer corev1informers.ConfigMapInformer,
|
||||||
loginDiscoveryConfigInformer placeholderv1alpha1informers.LoginDiscoveryConfigInformer,
|
loginDiscoveryConfigInformer placeholderv1alpha1informers.LoginDiscoveryConfigInformer,
|
||||||
|
withInformer withInformerOptionFunc,
|
||||||
) controller.Controller {
|
) controller.Controller {
|
||||||
return controller.New(
|
return controller.New(
|
||||||
controller.Config{
|
controller.Config{
|
||||||
@ -53,14 +73,14 @@ func NewPublisherController(
|
|||||||
loginDiscoveryConfigInformer: loginDiscoveryConfigInformer,
|
loginDiscoveryConfigInformer: loginDiscoveryConfigInformer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
controller.WithInformer(
|
withInformer(
|
||||||
configMapInformer,
|
configMapInformer,
|
||||||
controller.FilterFuncs{}, // TODO fix this and write tests
|
nameAndNamespaceExactMatchFilterFactory(clusterInfoName, clusterInfoNamespace),
|
||||||
controller.InformerOption{},
|
controller.InformerOption{},
|
||||||
),
|
),
|
||||||
controller.WithInformer(
|
withInformer(
|
||||||
loginDiscoveryConfigInformer,
|
loginDiscoveryConfigInformer,
|
||||||
controller.FilterFuncs{}, // TODO fix this and write tests
|
nameAndNamespaceExactMatchFilterFactory(configName, namespace),
|
||||||
controller.InformerOption{},
|
controller.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -29,8 +29,157 @@ import (
|
|||||||
placeholderinformers "github.com/suzerain-io/placeholder-name-client-go/pkg/generated/informers/externalversions"
|
placeholderinformers "github.com/suzerain-io/placeholder-name-client-go/pkg/generated/informers/externalversions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRun(t *testing.T) {
|
type ObservableWithInformerOption struct {
|
||||||
spec.Run(t, "publisher", func(t *testing.T, when spec.G, it spec.S) {
|
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"
|
const installedInNamespace = "some-namespace"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
@ -89,6 +238,7 @@ func TestRun(t *testing.T) {
|
|||||||
placeholderAPIClient,
|
placeholderAPIClient,
|
||||||
kubeInformers.Core().V1().ConfigMaps(),
|
kubeInformers.Core().V1().ConfigMaps(),
|
||||||
placeholderInformers.Placeholder().V1alpha1().LoginDiscoveryConfigs(),
|
placeholderInformers.Placeholder().V1alpha1().LoginDiscoveryConfigs(),
|
||||||
|
controller.WithInformer,
|
||||||
)
|
)
|
||||||
|
|
||||||
syncContext = &controller.Context{
|
syncContext = &controller.Context{
|
||||||
@ -131,7 +281,7 @@ func TestRun(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
when("the LoginDiscoveryConfig does not already exist", func() {
|
when("the LoginDiscoveryConfig does not already exist", func() {
|
||||||
it.Focus("creates a LoginDiscoveryConfig", func() {
|
it("creates a LoginDiscoveryConfig", func() {
|
||||||
startInformersAndController()
|
startInformersAndController()
|
||||||
err := controller.TestSync(t, subject, *syncContext)
|
err := controller.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
@ -287,23 +437,5 @@ func TestRun(t *testing.T) {
|
|||||||
r.Empty(placeholderAPIClient.Actions())
|
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{}))
|
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user