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

Commit d9eb636

Browse files
authored
Merge pull request #321 from timbyr/unpropogatedlabels
Support unpropagated labels
2 parents 564b4a9 + 179658c commit d9eb636

File tree

6 files changed

+75
-0
lines changed

6 files changed

+75
-0
lines changed

cmd/manager/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ var (
7070
webhookServerPort int
7171
restartOnSecretRefresh bool
7272
unpropagatedAnnotations arrayArg
73+
unpropagatedLabels arrayArg
7374
excludedNamespaces arrayArg
7475
managedNamespaceLabels arrayArg
7576
managedNamespaceAnnots arrayArg
@@ -148,6 +149,7 @@ func parseFlags() {
148149
flag.IntVar(&qps, "apiserver-qps-throttle", 50, "The maximum QPS to the API server. See the user guide for more information.")
149150
flag.BoolVar(&stats.SuppressObjectTags, "suppress-object-tags", true, "If true, suppresses the kinds of object metrics to reduce metric cardinality. See the user guide for more information.")
150151
flag.IntVar(&webhookServerPort, "webhook-server-port", 443, "The port that the webhook server serves at.")
152+
flag.Var(&unpropagatedLabels, "unpropagated-label", "An label that, if present, will be stripped out of any propagated copies of an object. May be specified multiple times, with each instance specifying one label. See the user guide for more information.")
151153
flag.Var(&unpropagatedAnnotations, "unpropagated-annotation", "An annotation that, if present, will be stripped out of any propagated copies of an object. May be specified multiple times, with each instance specifying one annotation. See the user guide for more information.")
152154
flag.Var(&excludedNamespaces, "excluded-namespace", "A namespace that, if present, will be excluded from HNC management. May be specified multiple times, with each instance specifying one namespace. See the user guide for more information.")
153155
flag.StringVar(&includedNamespacesRegex, "included-namespace-regex", ".*", "Namespace regular expression. Namespaces that match this regexp will be included and handle by HNC. The regex is implicitly wrapped by \"^...$\" and may only be specified once.")
@@ -163,6 +165,7 @@ func parseFlags() {
163165

164166
// Assign the array args to the configuration variables after the args are parsed.
165167
config.UnpropagatedAnnotations = unpropagatedAnnotations
168+
config.UnpropagatedLabels = unpropagatedLabels
166169

167170
// Assign the exclusion label args to the configuration
168171
for _, label := range nopropagationLabel {

config/crd/bases/hnc.x-k8s.io_hierarchicalresourcequotas.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,4 @@ spec:
9191
type: object
9292
served: true
9393
storage: true
94+
subresources: {}

docs/user-guide/how-to.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,14 @@ Interesting parameters include:
951951
used to remove an annotation on the source object that's has a special meaning
952952
to another system, such as GKE Config Sync. If you restart HNC after changing
953953
this arg, all _existing_ propagated objects will also be updated.
954+
* `--unpropagated-label=<string>`: empty by default, this argument
955+
can be specified multiple times, with each parameter representing an
956+
label name, such as `example.com/foo`. When HNC propagates objects from
957+
ancestor to descendant namespaces, it will strip these labels out of the
958+
metadata of the _copy_ of the object, if it exists. For example, this can be
959+
used to remove an label on the source object that's has a special meaning
960+
to another system, such as ArgoCD. If you restart HNC after changing
961+
this arg, all _existing_ propagated objects will also be updated.
954962
* `--apiserver-qps-throttle=<integer>`: set to 50 by default, this limits how many
955963
requests HNC will send to the Kubernetes apiserver per second in the steady
956964
state (it may briefly allow up to 50% more than this number). Setting this

internal/config/default_config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ package config
99
// times.
1010
var UnpropagatedAnnotations []string
1111

12+
// UnpropgatedLabels is a list of labels on objects that should _not_ be propagated by HNC.
13+
// Much like HNC itself, other systems (such as ArgoCD) use labels to "claim" an
14+
// object - such as deleting objects it doesn't recognize. By removing these labels on
15+
// propgated objects, HNC ensures that other systems won't attempt to claim the same object.
16+
//
17+
// This value is controlled by the --unpropagated-label command line, which may be set multiple
18+
// times.
19+
var UnpropagatedLabels []string
20+
1221
// NoPropagationLabel specifies a label Key and Value which will cause an object to be excluded
1322
// from propagation if the object defines that label with this specific value.
1423
type NoPropagationLabel struct {

internal/objects/reconciler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,11 @@ func cleanSource(src *unstructured.Unstructured) *unstructured.Unstructured {
503503
labels = map[string]string{}
504504
}
505505
labels[api.LabelManagedByApps] = api.MetaGroup
506+
507+
// Clean out bad labels.
508+
for _, unprop := range config.UnpropagatedLabels {
509+
delete(labels, unprop)
510+
}
506511
src.SetLabels(labels)
507512

508513
return src

internal/objects/reconciler_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ var _ = Describe("Basic propagation", func() {
389389

390390
// This is empty by default.
391391
config.UnpropagatedAnnotations = nil
392+
config.UnpropagatedLabels = nil
392393
})
393394

394395
AfterEach(func() {
@@ -777,6 +778,54 @@ var _ = Describe("Basic propagation", func() {
777778
}).Should(Succeed(), "waiting for annot-a to be unpropagated")
778779
})
779780

781+
It("should avoid propagating banned labels", func() {
782+
SetParent(ctx, barName, fooName)
783+
MakeObjectWithLabels(ctx, "roles", fooName, "foo-label-role", map[string]string{
784+
"label-a": "value-a",
785+
"label-b": "value-b",
786+
})
787+
788+
// Ensure the object is propagated with both labels
789+
Eventually(func() error {
790+
inst, err := GetObject(ctx, "roles", barName, "foo-label-role")
791+
if err != nil {
792+
return err
793+
}
794+
labels := inst.GetLabels()
795+
if labels["label-a"] != "value-a" {
796+
return fmt.Errorf("label-a: want 'value-a', got %q", labels["label-a"])
797+
}
798+
if labels["label-b"] != "value-b" {
799+
return fmt.Errorf("label-b: want 'value-b', got %q", labels["label-b"])
800+
}
801+
return nil
802+
}).Should(Succeed(), "waiting for initial sync of foo-label-role")
803+
DeleteObject(ctx, "roles", fooName, "foo-label-role")
804+
805+
// Tell the HNC config not to propagate label-a and verify that this time, it's not labelated
806+
config.UnpropagatedLabels = []string{"label-a"}
807+
MakeObjectWithLabels(ctx, "roles", fooName, "foo-label-role", map[string]string{
808+
"label-a": "value-a",
809+
"label-b": "value-b",
810+
})
811+
812+
// Verify that the label no longer appears
813+
Eventually(func() error {
814+
inst, err := GetObject(ctx, "roles", barName, "foo-label-role")
815+
if err != nil {
816+
return err
817+
}
818+
labels := inst.GetLabels()
819+
if val, ok := labels["label-a"]; ok {
820+
return fmt.Errorf("label-a: wanted it to be missing, got %q", val)
821+
}
822+
if labels["label-b"] != "value-b" {
823+
return fmt.Errorf("label-b: want 'value-b', got %q", labels["label-b"])
824+
}
825+
return nil
826+
}).Should(Succeed(), "waiting for label-a to be unpropagated")
827+
})
828+
780829
It("should avoid propagating when no selector is set if the sync mode is 'AllowPropagate'", func() {
781830
AddToHNCConfig(ctx, "", "secrets", api.AllowPropagate)
782831
// Set tree as bar -> foo(root).

0 commit comments

Comments
 (0)