Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.7.0-dev
v0.8.0
17 changes: 17 additions & 0 deletions pkg/clusters/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ func New(id string) *Cluster {
return c
}

// NewTestClusterFromClient creates a Cluster from a given client.
// Note that this method is meant for testing purposes only and it does not result in a fully functional Cluster.
// Calling anything except Client() on the resulting Cluster is undefined and might lead to panics or unexpected behavior.
func NewTestClusterFromClient(id string, cli client.Client) *Cluster {
c := &Cluster{}
c.InitializeID(id)
c.client = cli
return c
}

// WithConfigPath sets the config path for the cluster.
// Returns the cluster for chaining.
func (c *Cluster) WithConfigPath(cfgPath string) *Cluster {
Expand All @@ -51,6 +61,7 @@ func (c *Cluster) WithRESTConfig(cfg *rest.Config) *Cluster {
}

// RegisterConfigPathFlag adds a flag '--<id>-cluster' for the cluster's config path to the given flag set.
// If only a single kubeconfig is required, RegisterSingleConfigPathFlag can be used instead to have the flag named '--kubeconfig'.
// Panics if the cluster's id is not set.
func (c *Cluster) RegisterConfigPathFlag(flags *flag.FlagSet) {
if !c.HasID() {
Expand All @@ -59,6 +70,12 @@ func (c *Cluster) RegisterConfigPathFlag(flags *flag.FlagSet) {
flags.StringVar(&c.cfgPath, fmt.Sprintf("%s-cluster", c.id), "", fmt.Sprintf("Path to the %s cluster kubeconfig file or directory containing either a kubeconfig or host, token, and ca file. Leave empty to use in-cluster config.", c.id))
}

// RegisterSingleConfigPathFlag adds a '--kubeconfig' flag for the cluster's config path to the given flag set.
// If more than one kubeconfig is required, consider using RegisterConfigPathFlag instead, which is identical, but names the flag '--<id>-cluster'.
func (c *Cluster) RegisterSingleConfigPathFlag(flags *flag.FlagSet) {
flags.StringVar(&c.cfgPath, "kubeconfig", "", "Path to the kubeconfig file or directory containing either a kubeconfig or host, token, and ca file. Leave empty to use in-cluster config.")
}

// WithClientOptions allows to overwrite the default client options.
// It must be called before InitializeClient().
// Note that using this method disables the the scheme injection during client initialization.
Expand Down
17 changes: 17 additions & 0 deletions pkg/controller/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package controller
import (
"reflect"

"k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
Expand Down Expand Up @@ -179,6 +180,22 @@ func LostLabelPredicate(key, val string) predicate.Predicate {
}
}

// LabelSelectorPredicate returns a predicate based on a label selector.
// Opposed to the similarly named function from the controller-runtime library, this one works on label.Selector
// instead of metav1.LabelSelector.
func LabelSelectorPredicate(sel labels.Selector) predicate.Predicate {
return predicate.NewPredicateFuncs(func(obj client.Object) bool {
if obj == nil {
return false
}
ls := obj.GetLabels()
if ls == nil {
ls = map[string]string{}
}
return sel.Matches(labels.Set(ls))
})
}

/////////////////////////
/// STATUS PREDICATES ///
/////////////////////////
Expand Down
33 changes: 33 additions & 0 deletions pkg/controller/predicates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
Expand Down Expand Up @@ -114,8 +115,24 @@ var _ = Describe("Predicates", func() {
It("should detect changes to the labels", func() {
pHasFoo := ctrlutils.HasLabelPredicate("foo", "")
pHasBar := ctrlutils.HasLabelPredicate("bar", "")
matchesEverything := ctrlutils.LabelSelectorPredicate(labels.Everything())
matchesNothing := ctrlutils.LabelSelectorPredicate(labels.Nothing())
pHasFooWithFoo := ctrlutils.HasLabelPredicate("foo", "foo")
pHasFooWithBar := ctrlutils.HasLabelPredicate("foo", "bar")
fooWithFooSelector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "foo",
},
})
Expect(err).ToNot(HaveOccurred())
fooWithBarSelector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
})
Expect(err).ToNot(HaveOccurred())
pHasFooWithFooViaSelector := ctrlutils.LabelSelectorPredicate(fooWithFooSelector)
pHasFooWithBarViaSelector := ctrlutils.LabelSelectorPredicate(fooWithBarSelector)
pGotFoo := ctrlutils.GotLabelPredicate("foo", "")
pGotFooWithFoo := ctrlutils.GotLabelPredicate("foo", "foo")
pGotFooWithBar := ctrlutils.GotLabelPredicate("foo", "bar")
Expand All @@ -124,9 +141,13 @@ var _ = Describe("Predicates", func() {
pLostFooWithBar := ctrlutils.LostLabelPredicate("foo", "bar")
By("old and new resource are equal")
e := updateEvent(base, changed)
Expect(matchesEverything.Update(e)).To(BeTrue(), "'everything' LabelSelector should always match")
Expect(matchesNothing.Update(e)).To(BeFalse(), "'nothing' LabelSelector should never match")
Expect(pHasFoo.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithFoo.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithFooViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return false if the labels are not matched")
Expect(pHasFooWithBar.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithBarViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return falseif the labels are not matched")
Expect(pGotFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expect(pGotFooWithFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expect(pGotFooWithBar.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expand All @@ -138,10 +159,14 @@ var _ = Describe("Predicates", func() {
"foo": "foo",
})
e = updateEvent(base, changed)
Expect(matchesEverything.Update(e)).To(BeTrue(), "'everything' LabelSelector should always match")
Expect(matchesNothing.Update(e)).To(BeFalse(), "'nothing' LabelSelector should never match")
Expect(pHasFoo.Update(e)).To(BeTrue(), "HasLabelPredicate should return true if the label is there")
Expect(pHasBar.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if the label is not there")
Expect(pHasFooWithFoo.Update(e)).To(BeTrue(), "HasLabelPredicate should return true if the label is there and has the fitting value")
Expect(pHasFooWithFooViaSelector.Update(e)).To(BeTrue(), "LabelSelectorPredicate should return true if the labels are matched")
Expect(pHasFooWithBar.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if the label is there but has the wrong value")
Expect(pHasFooWithBarViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return false if the labels are not matched")
Expect(pGotFoo.Update(e)).To(BeTrue(), "GotLabelPredicate should return true if the label was added")
Expect(pGotFooWithFoo.Update(e)).To(BeTrue(), "GotLabelPredicate should return true if the label was added with the correct value")
Expect(pGotFooWithBar.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if the label was added but with the wrong value")
Expand All @@ -154,10 +179,14 @@ var _ = Describe("Predicates", func() {
"foo": "bar",
})
e = updateEvent(base, changed)
Expect(matchesEverything.Update(e)).To(BeTrue(), "'everything' LabelSelector should always match")
Expect(matchesNothing.Update(e)).To(BeFalse(), "'nothing' LabelSelector should never match")
Expect(pHasFoo.Update(e)).To(BeTrue(), "HasLabelPredicate should return true if the label is there")
Expect(pHasBar.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if the label is not there")
Expect(pHasFooWithFoo.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if the label is there but has the wrong value")
Expect(pHasFooWithFooViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return false if the labels are not matched")
Expect(pHasFooWithBar.Update(e)).To(BeTrue(), "HasLabelPredicate should return true if the label is there and has the fitting value")
Expect(pHasFooWithBarViaSelector.Update(e)).To(BeTrue(), "LabelSelectorPredicate should return true if the labels are matched")
Expect(pGotFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if the label was there before")
Expect(pGotFooWithFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if the label was changed but to the wrong value")
Expect(pGotFooWithBar.Update(e)).To(BeTrue(), "GotLabelPredicate should return true if the label was changed to the correct value")
Expand All @@ -168,9 +197,13 @@ var _ = Describe("Predicates", func() {
base = changed.DeepCopy()
changed.SetLabels(nil)
e = updateEvent(base, changed)
Expect(matchesEverything.Update(e)).To(BeTrue(), "'everything' LabelSelector should always match")
Expect(matchesNothing.Update(e)).To(BeFalse(), "'nothing' LabelSelector should never match")
Expect(pHasFoo.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithFoo.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithFooViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return false if the labels are not matched")
Expect(pHasFooWithBar.Update(e)).To(BeFalse(), "HasLabelPredicate should return false if there are no labels")
Expect(pHasFooWithBarViaSelector.Update(e)).To(BeFalse(), "LabelSelectorPredicate should return false if the labels are not matched")
Expect(pGotFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expect(pGotFooWithFoo.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expect(pGotFooWithBar.Update(e)).To(BeFalse(), "GotLabelPredicate should return false if there are no labels")
Expand Down