@@ -22,7 +22,6 @@ import (
2222 "errors"
2323 "fmt"
2424 "strconv"
25- "strings"
2625 "sync"
2726 "time"
2827
@@ -51,7 +50,6 @@ import (
5150 "sigs.k8s.io/controller-runtime/pkg/client/fake"
5251 "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
5352 "sigs.k8s.io/controller-runtime/pkg/config"
54- "sigs.k8s.io/controller-runtime/pkg/controller"
5553 "sigs.k8s.io/controller-runtime/pkg/event"
5654 "sigs.k8s.io/controller-runtime/pkg/log/zap"
5755 "sigs.k8s.io/controller-runtime/pkg/manager"
@@ -1511,132 +1509,146 @@ var _ = Describe("Reconciler", func() {
15111509
15121510 _ = Describe ("WithSelector" , func () {
15131511 var (
1514- mgr manager.Manager
1515- ctx context.Context
1516- cancel context.CancelFunc
1517- reconciledCRs []string
1518- matchingLabels map [string ]string
1519- reconciledCRsMutex sync.Mutex
1520- labeledObj * unstructured.Unstructured
1521- unlabeledObj * unstructured.Unstructured
1522- labeledObjKey types.NamespacedName
1523- unlabeledObjKey types.NamespacedName
1512+ ctx context.Context
1513+ cancel context.CancelFunc
1514+ mgr manager.Manager
1515+ reconciledCRs []string
1516+ anotherReconciledCRs []string
1517+ matchingLabels map [string ]string
1518+ anotherMatchingLabels map [string ]string
1519+ labeledObj * unstructured.Unstructured
1520+ anotherObj * unstructured.Unstructured
1521+ labeledObjKey types.NamespacedName
1522+ anotherObjKey types.NamespacedName
1523+ mu sync.Mutex
15241524 )
15251525
15261526 BeforeEach (func () {
1527- reconciledCRs = []string {}
1528- mgr = getManagerOrFail ()
1529- matchingLabels = map [string ]string {"app" : "foo" }
1530-
1531- r , err := New (
1532- WithGroupVersionKind (gvk ),
1533- WithChart (chrt ),
1534- WithSelector (metav1.LabelSelector {MatchLabels : matchingLabels }),
1535- )
1536- Expect (err ).ToNot (HaveOccurred ())
1527+ ctx , cancel = context .WithCancel (context .Background ())
15371528
1538- reconciler := reconcile .Func (func (ctx context.Context , req reconcile.Request ) (reconcile.Result , error ) {
1539- reconciledCRsMutex .Lock ()
1540- reconciledCRs = append (reconciledCRs , req .NamespacedName .String ())
1541- reconciledCRsMutex .Unlock ()
1542- return r .Reconcile (ctx , req )
1543- })
1529+ mu .Lock ()
1530+ reconciledCRs = nil
1531+ anotherReconciledCRs = nil
1532+ mu .Unlock ()
15441533
1545- controllerName := fmt .Sprintf ("%v-controller" , strings .ToLower (gvk .Kind ))
1546- Expect (r .addDefaults (mgr , controllerName )).To (Succeed ())
1547- r .setupScheme (mgr )
1534+ matchingLabels = map [string ]string {"app" : "foo" }
1535+ anotherMatchingLabels = map [string ]string {"app" : "bar" }
15481536
1549- c , err := controller .New (controllerName , mgr , controller.Options {
1550- Reconciler : reconciler ,
1551- MaxConcurrentReconciles : 1 ,
1537+ trackingHook := hook .PostHookFunc (func (obj * unstructured.Unstructured , rel release.Release , log logr.Logger ) error {
1538+ mu .Lock ()
1539+ defer mu .Unlock ()
1540+ reconciledCRs = append (reconciledCRs , obj .GetName ())
1541+ return nil
15521542 })
1553- Expect (err ).ToNot (HaveOccurred ())
1554- Expect (r .setupWatches (mgr , c )).To (Succeed ())
1543+ mgr = setupManagerWithPostHook (ctx , trackingHook , matchingLabels )
15551544
15561545 labeledObj = testutil .BuildTestCR (gvk )
15571546 labeledObj .SetName ("labeled-cr" )
15581547 labeledObj .SetLabels (matchingLabels )
15591548 labeledObjKey = types.NamespacedName {Namespace : labeledObj .GetNamespace (), Name : labeledObj .GetName ()}
15601549
1561- unlabeledObj = testutil .BuildTestCR (gvk )
1562- unlabeledObj .SetName ("unlabeled-cr" )
1563- unlabeledObjKey = types.NamespacedName {Namespace : unlabeledObj .GetNamespace (), Name : unlabeledObj .GetName ()}
1564-
1565- ctx , cancel = context .WithCancel (context .Background ())
1566- go func () {
1567- Expect (mgr .Start (ctx )).To (Succeed ())
1568- }()
1569- Expect (mgr .GetCache ().WaitForCacheSync (ctx )).To (BeTrue ())
1550+ anotherObj = testutil .BuildTestCR (gvk )
1551+ anotherObj .SetName ("another-cr" )
1552+ anotherObjKey = types.NamespacedName {Namespace : anotherObj .GetNamespace (), Name : anotherObj .GetName ()}
15701553 })
15711554
15721555 AfterEach (func () {
15731556 By ("ensuring the labeled CR is deleted" , func () {
1574- err := mgr .GetAPIReader ().Get (ctx , labeledObjKey , labeledObj )
1575- if apierrors .IsNotFound (err ) {
1576- return
1577- }
1578- Expect (err ).ToNot (HaveOccurred ())
1579- labeledObj .SetFinalizers ([]string {})
1580- Expect (mgr .GetClient ().Update (ctx , labeledObj )).To (Succeed ())
1581- Expect (mgr .GetClient ().Delete (ctx , labeledObj )).To (Succeed ())
1557+ ensureDeleteCR (ctx , mgr , labeledObjKey , labeledObj )
15821558 })
15831559
15841560 By ("ensuring the unlabeled CR is deleted" , func () {
1585- err := mgr .GetAPIReader ().Get (ctx , unlabeledObjKey , unlabeledObj )
1586- if apierrors .IsNotFound (err ) {
1587- return
1588- }
1589- Expect (err ).ToNot (HaveOccurred ())
1590- unlabeledObj .SetFinalizers ([]string {})
1591- Expect (mgr .GetClient ().Update (ctx , unlabeledObj )).To (Succeed ())
1592- Expect (mgr .GetClient ().Delete (ctx , unlabeledObj )).To (Succeed ())
1561+ ensureDeleteCR (ctx , mgr , anotherObjKey , anotherObj )
15931562 })
1594-
15951563 cancel ()
15961564 })
15971565
15981566 It ("should only reconcile CRs matching the label selector" , func () {
1567+ By ("creating a CR without matching labels" , func () {
1568+ Expect (mgr .GetClient ().Create (ctx , anotherObj )).To (Succeed ())
1569+ })
1570+
1571+ By ("verifying that the labeled reconciler does not reconcile CR without labels" , func () {
1572+ Consistently (func () []string {
1573+ mu .Lock ()
1574+ defer mu .Unlock ()
1575+ return reconciledCRs
1576+ }, "2s" , "100ms" ).Should (BeEmpty ())
1577+ })
1578+
15991579 By ("creating a CR with matching labels" , func () {
16001580 Expect (mgr .GetClient ().Create (ctx , labeledObj )).To (Succeed ())
16011581 })
16021582
1603- By ("creating a CR without matching labels" , func () {
1604- Expect (mgr .GetClient ().Create (ctx , unlabeledObj )).To (Succeed ())
1583+ By ("verifying only the labeled CR was reconciled" , func () {
1584+ Eventually (func () []string {
1585+ mu .Lock ()
1586+ defer mu .Unlock ()
1587+ return reconciledCRs
1588+ }).Should (HaveExactElements (labeledObjKey .Name ))
1589+ })
1590+
1591+ By ("updating the unlabeled CR to have matching labels" , func () {
1592+ Expect (mgr .GetClient ().Get (ctx , anotherObjKey , anotherObj )).To (Succeed ())
1593+ anotherObj .SetLabels (matchingLabels )
1594+ Expect (mgr .GetClient ().Update (ctx , anotherObj )).To (Succeed ())
16051595 })
16061596
1607- By ("waiting for reconciliations to complete " , func () {
1597+ By ("verifying that both CRs were reconciled after setting label to the unlabeled CR " , func () {
16081598 Eventually (func () []string {
1609- reconciledCRsMutex .Lock ()
1610- defer reconciledCRsMutex .Unlock ()
1599+ mu .Lock ()
1600+ defer mu .Unlock ()
16111601 return reconciledCRs
1612- }, "5s " , "100ms" ).Should (ContainElement (labeledObjKey .String () ))
1602+ }, "10s " , "100ms" ).Should (ContainElements (labeledObjKey .Name , anotherObjKey . Name ))
16131603 })
1604+ })
16141605
1615- By ("verifying only the labeled CR was reconciled" , func () {
1616- reconciledCRsMutex .Lock ()
1617- defer reconciledCRsMutex .Unlock ()
1618- Expect (reconciledCRs ).To (ContainElement (labeledObjKey .String ()))
1619- Expect (reconciledCRs ).NotTo (ContainElement (unlabeledObjKey .String ()))
1606+ It ("should reconcile CRs independently when using two managers with different label selectors" , func () {
1607+ By ("creating another manager with a different label selector" , func () {
1608+ postHook := hook .PostHookFunc (func (obj * unstructured.Unstructured , rel release.Release , log logr.Logger ) error {
1609+ mu .Lock ()
1610+ defer mu .Unlock ()
1611+ anotherReconciledCRs = append (anotherReconciledCRs , obj .GetName ())
1612+ return nil
1613+ })
1614+ _ = setupManagerWithPostHook (ctx , postHook , anotherMatchingLabels )
16201615 })
16211616
1622- By ("updating the unlabeled CR to have matching labels" , func () {
1623- Expect (mgr .GetClient ().Get (ctx , unlabeledObjKey , unlabeledObj )).To (Succeed ())
1624- unlabeledObj .SetLabels (matchingLabels )
1625- Expect (mgr .GetClient ().Update (ctx , unlabeledObj )).To (Succeed ())
1617+ By ("creating a CR with matching labels for the first manager" , func () {
1618+ Expect (mgr .GetClient ().Create (ctx , labeledObj )).To (Succeed ())
16261619 })
16271620
1628- By ("waiting for the previously unlabeled CR to be reconciled " , func () {
1621+ By ("verifying that only the first manager reconciled the CR " , func () {
16291622 Eventually (func () []string {
1630- reconciledCRsMutex .Lock ()
1631- defer reconciledCRsMutex .Unlock ()
1623+ mu .Lock ()
1624+ defer mu .Unlock ()
16321625 return reconciledCRs
1633- }, "5s" , "100ms" ).Should (ContainElement (unlabeledObjKey .String ()))
1626+ }, "10s" , "100ms" ).Should (HaveExactElements (labeledObjKey .Name ))
1627+
1628+ Consistently (func () []string {
1629+ mu .Lock ()
1630+ defer mu .Unlock ()
1631+ return anotherReconciledCRs
1632+ }, "2s" , "100ms" ).Should (BeEmpty ())
16341633 })
16351634
1636- By ("verifying the previously unlabeled CR was reconciled after label change" , func () {
1637- reconciledCRsMutex .Lock ()
1638- defer reconciledCRsMutex .Unlock ()
1639- Expect (reconciledCRs ).To (ContainElement (unlabeledObjKey .String ()))
1635+ By ("creating a CR with matching labels for the second manager" , func () {
1636+ anotherObj .SetLabels (anotherMatchingLabels )
1637+ Expect (mgr .GetClient ().Create (ctx , anotherObj )).To (Succeed ())
1638+ })
1639+
1640+ By ("verifying that both managers reconcile only matching labels CRs" , func () {
1641+ Eventually (func () []string {
1642+ mu .Lock ()
1643+ defer mu .Unlock ()
1644+ return reconciledCRs
1645+ }, "10s" , "100ms" ).Should (HaveExactElements (labeledObjKey .Name ))
1646+
1647+ Eventually (func () []string {
1648+ mu .Lock ()
1649+ defer mu .Unlock ()
1650+ return anotherReconciledCRs
1651+ }, "10s" , "100ms" ).Should (HaveExactElements (anotherObjKey .Name ))
16401652 })
16411653 })
16421654 })
@@ -1839,3 +1851,31 @@ func verifyEvent(ctx context.Context, cl client.Reader, obj metav1.Object, event
18391851 Reason: %q
18401852 Message: %q` , eventType , reason , message ))
18411853}
1854+
1855+ func ensureDeleteCR (ctx context.Context , mgr manager.Manager , crKey types.NamespacedName , cr * unstructured.Unstructured ) {
1856+ err := mgr .GetAPIReader ().Get (ctx , crKey , cr )
1857+ if apierrors .IsNotFound (err ) {
1858+ return
1859+ }
1860+ Expect (err ).ToNot (HaveOccurred ())
1861+ cr .SetFinalizers ([]string {})
1862+ Expect (mgr .GetClient ().Update (ctx , cr )).To (Succeed ())
1863+ Expect (mgr .GetClient ().Delete (ctx , cr )).To (Succeed ())
1864+ }
1865+
1866+ func setupManagerWithPostHook (ctx context.Context , postHook hook.PostHook , matchingLabels map [string ]string ) manager.Manager {
1867+ mgr := getManagerOrFail ()
1868+ r , err := New (
1869+ WithGroupVersionKind (gvk ),
1870+ WithChart (chrt ),
1871+ WithSelector (metav1.LabelSelector {MatchLabels : matchingLabels }),
1872+ WithPostHook (postHook ),
1873+ )
1874+ Expect (err ).ToNot (HaveOccurred ())
1875+ Expect (r .SetupWithManager (mgr )).To (Succeed ())
1876+ go func () {
1877+ Expect (mgr .Start (ctx )).To (Succeed ())
1878+ }()
1879+ Expect (mgr .GetCache ().WaitForCacheSync (ctx )).To (BeTrue ())
1880+ return mgr
1881+ }
0 commit comments