Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

Commit b35e79d

Browse files
authored
Merge pull request #80 from joe2far/fix-hierarchy-excluded-conflict
Fix hierarchy conflict validation excluding non-propagated objects
2 parents 6b5a9f8 + f959973 commit b35e79d

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

internal/validators/hierarchy.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
2323
"sigs.k8s.io/hierarchical-namespaces/internal/config"
2424
"sigs.k8s.io/hierarchical-namespaces/internal/forest"
25+
"sigs.k8s.io/hierarchical-namespaces/internal/pkg/selectors"
2526
)
2627

2728
const (
@@ -250,11 +251,12 @@ func (v *Hierarchy) getConflictingObjectsOfType(gvk schema.GroupVersionKind, new
250251
// Get all the source objects in the new ancestors that would be propagated
251252
// into the descendants.
252253
newAnsSrcObjs := make(map[string]bool)
253-
// TODO additionally check if the ancestor source objects obey the
254-
// 'shouldPropagateSource()' rules from the reconcilers/object.go. Only
255-
// propagatable ancestor source would cause overwriting conflict.
256254
for _, o := range newParent.GetAncestorSourceObjects(gvk, "") {
257-
newAnsSrcObjs[o.GetName()] = true
255+
// If the user has chosen not to propagate the object to this descendant,
256+
// then it should not be included in conflict checks
257+
if ok, _ := selectors.ShouldPropagate(o, o.GetLabels()); ok {
258+
newAnsSrcObjs[o.GetName()] = true
259+
}
258260
}
259261

260262
// Look in the descendants to find if there's any conflict.

internal/validators/hierarchy_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
. "github.com/onsi/gomega"
88
authn "k8s.io/api/authentication/v1"
99
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1011
"k8s.io/apimachinery/pkg/runtime/schema"
1112
"sigs.k8s.io/controller-runtime/pkg/log/zap"
1213

@@ -158,6 +159,58 @@ func TestChangeParentWithConflict(t *testing.T) {
158159
}
159160
}
160161

162+
func TestConflictItemWithPropagateNoneLabel(t *testing.T) {
163+
f := foresttest.Create("-a-c") // a <- b; c <- d
164+
gvk := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"}
165+
or := &reconcilers.ObjectReconciler{
166+
GVK: gvk,
167+
Mode: api.Propagate,
168+
}
169+
f.AddTypeSyncer(or)
170+
171+
// Create conflict secret annotated with propagate none as true
172+
inst := &unstructured.Unstructured{}
173+
inst.SetName("conflict")
174+
inst.SetNamespace("a")
175+
inst.SetGroupVersionKind(gvk)
176+
inst.SetAnnotations(map[string]string{api.AnnotationNoneSelector: "true"})
177+
f.Get("a").SetSourceObject(inst)
178+
// Create secret with the same name in namespace 'b' and 'd'
179+
createSecret("conflict", "c", f)
180+
createSecret("conflict", "d", f)
181+
182+
h := &Hierarchy{Forest: f}
183+
l := zap.New()
184+
tests := []struct {
185+
name string
186+
nnm string
187+
pnm string
188+
fail bool
189+
}{
190+
{name: "ok: no conflict as parent secret is propagate none", nnm: "c", pnm: "a"},
191+
{name: "conflict secret in parent (child secret is propagate none)", nnm: "a", pnm: "d", fail: true},
192+
}
193+
194+
for _, tc := range tests {
195+
t.Run(tc.name, func(t *testing.T) {
196+
// Setup
197+
g := NewWithT(t)
198+
hc := &api.HierarchyConfiguration{Spec: api.HierarchyConfigurationSpec{Parent: tc.pnm}}
199+
hc.ObjectMeta.Name = api.Singleton
200+
hc.ObjectMeta.Namespace = tc.nnm
201+
req := &request{hc: hc}
202+
203+
// Test
204+
got := h.handle(context.Background(), l, req)
205+
206+
// Report
207+
logResult(t, got.AdmissionResponse.Result)
208+
g.Expect(got.AdmissionResponse.Allowed).ShouldNot(Equal(tc.fail))
209+
})
210+
}
211+
212+
}
213+
161214
func TestAuthz(t *testing.T) {
162215
tests := []struct {
163216
name string

0 commit comments

Comments
 (0)