Skip to content

Commit 7c2bddc

Browse files
committed
Revert independent doNotDeploy behavior
1 parent 4bf96e3 commit 7c2bddc

3 files changed

Lines changed: 37 additions & 44 deletions

File tree

integrationtests/controller/bundle/bundle_targets_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,22 +459,23 @@ var _ = Describe("Bundle targets", Ordered, func() {
459459
})
460460
})
461461

462-
// Regression test for https://github.com/rancher/fleet/issues/3580:
462+
// With FirstMatch semantics (the default), only the first matching targetCustomization is applied.
463463
// When a broader-matching target appears before a doNotDeploy target in the list,
464-
// the doNotDeploy target was previously bypassed due to first-match semantics.
464+
// the broader match wins and the doNotDeploy entry is never evaluated.
465+
// Users must order their targetCustomizations from specific to general to use doNotDeploy effectively.
465466
When("a broader-matching targetCustomization appears before a doNotDeploy targetCustomization", func() {
466467
BeforeEach(func() {
467468
bundleName = "donot-deploy-after-broader-match"
468469
bdLabels = map[string]string{
469470
"fleet.cattle.io/bundle-name": bundleName,
470471
"fleet.cattle.io/bundle-namespace": namespace,
471472
}
472-
expectedNumberOfBundleDeployments = 0
473+
expectedNumberOfBundleDeployments = 1
473474
// simulate targets in fleet.yaml:
474475
// - first entry matches all clusters (broader match)
475476
// - second entry matches cluster "one" with doNotDeploy=true
476-
// With the old first-match logic, cluster "one" would match the first entry and
477-
// the doNotDeploy entry would never be evaluated.
477+
// With FirstMatch semantics, cluster "one" matches the first entry and gets deployed.
478+
// The doNotDeploy entry is never evaluated because the first match wins.
478479
targets = []v1alpha1.BundleTarget{
479480
{
480481
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{
@@ -500,7 +501,7 @@ var _ = Describe("Bundle targets", Ordered, func() {
500501
targets = append(targets, targetsInGitRepo...)
501502
})
502503

503-
It("no BundleDeployments are created", func() {
504+
It("creates a BundleDeployment because first match wins", func() {
504505
waitForBundleToBeReady(bundleName)
505506
_ = verifyBundlesDeploymentsAreCreated(expectedNumberOfBundleDeployments, bdLabels, bundleName)
506507
})

internal/cmd/controller/target/builder.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func (m *Manager) Targets(ctx context.Context, bundle *fleet.Bundle, manifestID
7272
if err != nil {
7373
return nil, false, err
7474
}
75+
clusterLoop:
7576
for _, cluster := range clusters.Items {
7677
logger.V(4).Info("Cluster has namespace?", "cluster", cluster.Name, "namespace", cluster.Status.Namespace)
7778
clusterGroups, err := m.clusterGroupsForCluster(ctx, &cluster)
@@ -85,28 +86,50 @@ func (m *Manager) Targets(ctx context.Context, bundle *fleet.Bundle, manifestID
8586
if target == nil {
8687
continue
8788
}
88-
// Check all matching targetCustomizations for doNotDeploy, not just the first match.
89-
// This ensures that a doNotDeploy entry is honoured even when a broader-matching
90-
// target appears before it in the target list (fixes first-match bypass).
91-
doNotDeploy := target.DoNotDeploy || bm.HasDoNotDeployTarget(cluster.Name, clusterGroupsAsLabelMap, cluster.Labels)
92-
if doNotDeploy {
89+
// Check if the GitRepo target has doNotDeploy set
90+
if target.DoNotDeploy {
9391
logger.V(1).Info("Skipping BundleDeployment creation because doNotDeploy is set to true.",
9492
"bundle", bundle.Name,
9593
"bundleNamespace", bundle.Namespace,
9694
"cluster", cluster.Name,
9795
"clusterNamespace", cluster.Namespace,
98-
"reason", "doNotDeploy",
96+
"reason", "doNotDeploy on GitRepo target",
9997
)
10098
continue
10199
}
102100
// check if there is any matching targetCustomization that should be applied
103101
targetOpts := target.BundleDeploymentOptions
104102
if bundle.Spec.TargetCustomizationMode == fleet.TargetCustomizationModeAllMatches {
105-
for _, tc := range bm.MatchAllTargetCustomizations(cluster.Name, clusterGroupsAsLabelMap, cluster.Labels) {
103+
// AllMatches mode: merge all matching customizations
104+
// Check if any matching customization has doNotDeploy=true (OR logic)
105+
matchedCustomizations := bm.MatchAllTargetCustomizations(cluster.Name, clusterGroupsAsLabelMap, cluster.Labels)
106+
for _, tc := range matchedCustomizations {
107+
if tc.DoNotDeploy {
108+
logger.V(1).Info("Skipping BundleDeployment creation because doNotDeploy is set to true.",
109+
"bundle", bundle.Name,
110+
"bundleNamespace", bundle.Namespace,
111+
"cluster", cluster.Name,
112+
"clusterNamespace", cluster.Namespace,
113+
"reason", "doNotDeploy on targetCustomization (AllMatches mode)",
114+
)
115+
continue clusterLoop
116+
}
106117
targetOpts = options.Merge(targetOpts, tc.BundleDeploymentOptions)
107118
}
108119
} else {
120+
// FirstMatch mode: apply only the first matching customization
109121
if targetCustomized := bm.MatchTargetCustomizations(cluster.Name, clusterGroupsAsLabelMap, cluster.Labels); targetCustomized != nil {
122+
// Check if the first matching targetCustomization has doNotDeploy set
123+
if targetCustomized.DoNotDeploy {
124+
logger.V(1).Info("Skipping BundleDeployment creation because doNotDeploy is set to true.",
125+
"bundle", bundle.Name,
126+
"bundleNamespace", bundle.Namespace,
127+
"cluster", cluster.Name,
128+
"clusterNamespace", cluster.Namespace,
129+
"reason", "doNotDeploy on targetCustomization (FirstMatch mode)",
130+
)
131+
continue
132+
}
110133
targetOpts = targetCustomized.BundleDeploymentOptions
111134
}
112135
}

internal/cmd/controller/target/matcher/bundlematch.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,6 @@ func (a *BundleMatch) MatchAllTargetCustomizations(clusterName string, clusterGr
7575
return result
7676
}
7777

78-
// HasDoNotDeployTarget returns true if any bundle target matching the given cluster
79-
// has DoNotDeploy set to true. Unlike MatchTargetCustomizations, this scans all matching
80-
// bundle targets instead of stopping at the first match, so a doNotDeploy entry does not have to
81-
// appear before a broader-matching entry in the target list.
82-
func (a *BundleMatch) HasDoNotDeployTarget(clusterName string, clusterGroups map[string]map[string]string, clusterLabels map[string]string) bool {
83-
for _, tm := range a.matcher.matches {
84-
if !tm.bundleTarget.DoNotDeploy {
85-
continue
86-
}
87-
if len(clusterGroups) == 0 {
88-
if criteriaWithoutRestrictions(tm, clusterName, "", nil, clusterLabels) {
89-
return true
90-
}
91-
} else {
92-
for cg, cgLabels := range clusterGroups {
93-
if criteriaWithoutRestrictions(tm, clusterName, cg, cgLabels, clusterLabels) {
94-
return true
95-
}
96-
}
97-
}
98-
}
99-
return false
100-
}
101-
10278
type targetMatch struct {
10379
bundleTarget *fleet.BundleTarget
10480
criteria *ClusterMatcher
@@ -190,13 +166,6 @@ func (m *matcher) criteriaWithRestrictions(targetMatch targetMatch, clusterName,
190166
return false
191167
}
192168

193-
// criteriaWithoutRestrictions checks targetMatch's criteria for a match on the specified cluster
194-
// name, group and labels, without checking if target is inside the targetRestrictions.
195-
// This is used for TargetCustomizations.
196-
func criteriaWithoutRestrictions(targetMatch targetMatch, clusterName, clusterGroup string, clusterGroupLabels, clusterLabels map[string]string) bool {
197-
return targetMatch.criteria.Match(clusterName, clusterGroup, clusterGroupLabels, clusterLabels)
198-
}
199-
200169
// match returns the first BundleTarget, from the matcher's target matches, which matches the specified cluster name, groups and labels, using matching logic implemented via findCriteriaMatch.
201170
func (m *matcher) match(clusterName string, clusterLabels map[string]string, clusterGroups map[string]map[string]string, findCriteriaMatch findCriteriaMatch) *fleet.BundleTarget {
202171
for _, targetMatch := range m.matches {

0 commit comments

Comments
 (0)