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

Commit b04dd8e

Browse files
committed
adding new --exclude-resources-with-label manager CLI argument
Changed default exclusion by label mechanism to use this CLI argument instead of a hardcoded list of labels. Moved the default Rancher label exclusion to be a default CLI argument on the manager. Fixed a bug that caused excluded resources to be propagated with the propagate.hnc.x-k8s.io/all annotation. Tested: made sure the current test for default exclusion fails after my CLI argument change, changed the test to reflect the changes, test now passes as expected. Wrote a test that verifies the propagate.hnc.x-k8s.io/all annotation bug doesn't occur, which failed before the bugfix. Executed e2e tests and they pass. Manually tested the manager by adding the new CLI argument and with that a labeled resource was skipped, then removed the argument and it has propagated. Did the same with two different annotations specified together as two CLI arguments, and resources that had any of those labels were skipped as expected. Manually tried to cause an excluded resource to propagate by adding the propagate.hnc.x-k8s.io/all annotation, and it didn't propagate.
1 parent 0fc9d45 commit b04dd8e

File tree

7 files changed

+74
-18
lines changed

7 files changed

+74
-18
lines changed

cmd/manager/main.go

+23
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818
import (
1919
"errors"
2020
"flag"
21+
"fmt"
2122
"net/http"
2223
"os"
2324
"strings"
@@ -72,6 +73,7 @@ var (
7273
excludedNamespaces arrayArg
7374
managedNamespaceLabels arrayArg
7475
managedNamespaceAnnots arrayArg
76+
nopropagationLabel arrayArg
7577
includedNamespacesRegex string
7678
webhooksOnly bool
7779
enableHRQ bool
@@ -156,10 +158,31 @@ func parseFlags() {
156158
flag.BoolVar(&enableHRQ, "enable-hrq", false, "Enables hierarchical resource quotas")
157159
flag.StringVar(&hncNamespace, "namespace", "hnc-system", "Namespace where hnc-manager and hnc resources deployed")
158160
flag.DurationVar(&hrqSyncInterval, "hrq-sync-interval", 1*time.Minute, "Frequency to double-check that all HRQ usages are up-to-date (shouldn't be needed)")
161+
flag.Var(&nopropagationLabel, "nopropagation-label", "A label specified as key=val that, if present, will cause HNC to skip objects that match this label. May be specified multiple times, with each key=value pair specifying one label. See the user guide for more information.")
159162
flag.Parse()
160163

161164
// Assign the array args to the configuration variables after the args are parsed.
162165
config.UnpropagatedAnnotations = unpropagatedAnnotations
166+
167+
// Assign the exclusion label args to the configuration
168+
for _, label := range nopropagationLabel {
169+
keyVal := strings.Split(label, "=")
170+
if len(keyVal) != 2 {
171+
setupLog.Info(fmt.Sprintf("--nopropagation-label must contain exactly one equal sign (=): %s", label))
172+
os.Exit(1)
173+
}
174+
labelKey := keyVal[0]
175+
labelValue := keyVal[1]
176+
177+
if len(labelKey) == 0 {
178+
setupLog.Info(fmt.Sprintf("--nopropagation-label must not have an empty key for the label: %s", label))
179+
os.Exit(1)
180+
}
181+
182+
setupLog.Info(fmt.Sprintf("Will exclude objects that match label %s", label))
183+
config.NoPropagationLabels = append(config.NoPropagationLabels, config.NoPropagationLabel{Key: labelKey, Value: labelValue})
184+
}
185+
163186
config.SetNamespaces(includedNamespacesRegex, excludedNamespaces...)
164187
if err := config.SetManagedMeta(managedNamespaceLabels, managedNamespaceAnnots); err != nil {
165188
setupLog.Error(err, "Illegal flag values")

config/manager/manager.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ spec:
4949
- "--excluded-namespace=kube-public"
5050
- "--excluded-namespace=hnc-system"
5151
- "--excluded-namespace=kube-node-lease"
52+
# Preserves the existing behavior of skipping Rancher objects.
53+
# Please don't add any more nopropagation labels to the list of args.
54+
- "--nopropagation-label=cattle.io/creator=norman"
5255
ports:
5356
- containerPort: 9443
5457
name: webhook-server

docs/user-guide/concepts.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,10 @@ objects from being propagated by HNC.
445445
auto-created in new namespaces by Istio and Kubernetes respectively
446446
* Any objects with the label
447447
`cattle.io/creator:norman`, which are [inserted by Rancher to support
448-
Projects](https://rancher.com/docs/rancher/v2.6/en/system-tools/#remove))
448+
Projects](https://rancher.com/docs/rancher/v2.6/en/system-tools/#remove)).
449+
Can be disabled by removing the default command line argument on the manager
450+
`--nopropagation-label=cattle.io/creator=norman`. Refer to [How-to:
451+
Modify command-line arguments](how-to.md#modify-command-line-arguments) for more details.
449452
* *HNC v1.1+:* Secrets with type `helm.sh/release.v1`, which is auto-created in
450453
the namespaces where their respective Helm releases are deployed to.
451454

docs/user-guide/how-to.md

+9
Original file line numberDiff line numberDiff line change
@@ -972,3 +972,12 @@ Interesting parameters include:
972972
load on your metrics database (through increased metric cardinality) and also
973973
by increasing how carefully you need to guard your metrics against
974974
unauthorized viewers.
975+
* `--nopropagation-label`: has the same effect as the `propagate.hnc.x-k8s.io/none`
976+
annotation as specified in [limiting propagation](how-to.md#limit-the-propagation-of-an-object-to-descendant-namespaces),
977+
but is useful when there's no control over what annotations the object has in order
978+
to disable the propagation of that object. This argument may be specified multiple
979+
times, with each parameter representing one `key=val` pair of a label that should
980+
exclude an object from propagation.
981+
* Rancher objects that have the label `cattle.io/creator=norman` are not propagated
982+
by the default manifests (refer to [Concepts: built in exceptions](concepts.md#built-in-exceptions)
983+
for more information).

internal/config/default_config.go

+11
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,14 @@ package config
88
// This value is controlled by the --unpropagated-annotation command line, which may be set multiple
99
// times.
1010
var UnpropagatedAnnotations []string
11+
12+
// NoPropagationLabel specifies a label Key and Value which will cause an object to be excluded
13+
// from propagation if the object defines that label with this specific value.
14+
type NoPropagationLabel struct {
15+
Key string
16+
Value string
17+
}
18+
19+
// NoPropagationLabels is a configuration slice that contains all NoPropagationLabel labels that should
20+
// cause objects to be ignored from propagation.
21+
var NoPropagationLabels []NoPropagationLabel

internal/objects/reconciler_test.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -446,15 +446,20 @@ var _ = Describe("Basic propagation", func() {
446446
Eventually(HasObject(ctx, "secrets", barName, "helm-secret")).Should(BeFalse())
447447
})
448448

449-
It("should not propagate builtin exclusions by labels", func() {
449+
It("should not propagate objects excluded by labels", func() {
450450
SetParent(ctx, barName, fooName)
451+
config.NoPropagationLabels = append(config.NoPropagationLabels, config.NoPropagationLabel{Key: "cattle.io/creator", Value: "norman"})
452+
config.NoPropagationLabels = append(config.NoPropagationLabels, config.NoPropagationLabel{Key: "ignore-label", Value: "label"})
453+
451454
MakeObjectWithLabels(ctx, "roles", fooName, "role-with-labels-blocked", map[string]string{"cattle.io/creator": "norman"})
455+
MakeObjectWithLabels(ctx, "roles", fooName, "role-with-labels-blocked-2", map[string]string{"ignore-label": "label"})
452456
MakeObjectWithLabels(ctx, "roles", fooName, "role-with-labels-wrong-value", map[string]string{"cattle.io/creator": "testme"})
453457
MakeObjectWithLabels(ctx, "roles", fooName, "role-with-labels-something", map[string]string{"app": "hello-world"})
454458
AddToHNCConfig(ctx, api.RBACGroup, api.RoleKind, api.Propagate)
455459

456460
// the first one should not propagate, everything else should
457461
Consistently(HasObject(ctx, "roles", barName, "role-with-labels-blocked")).Should(BeFalse())
462+
Consistently(HasObject(ctx, "roles", barName, "role-with-labels-blocked-2")).Should(BeFalse())
458463
Eventually(HasObject(ctx, "roles", barName, "role-with-labels-wrong-value")).Should(BeTrue())
459464
Eventually(HasObject(ctx, "roles", barName, "role-with-labels-something")).Should(BeTrue())
460465

@@ -467,6 +472,18 @@ var _ = Describe("Basic propagation", func() {
467472
Eventually(HasObject(ctx, "configmaps", barName, "cm-with-label-2")).Should(BeTrue())
468473
})
469474

475+
It("should not propagate objects excluded by labels when using all annotation", func() {
476+
SetParent(ctx, barName, fooName)
477+
config.NoPropagationLabels = append(config.NoPropagationLabels, config.NoPropagationLabel{Key: "cattle.io/creator", Value: "norman"})
478+
479+
MakeObjectWithLabels(ctx, "roles", fooName, "role-with-labels-blocked", map[string]string{"cattle.io/creator": "norman"})
480+
UpdateObjectWithAnnotations(ctx, "roles", fooName, "role-with-labels-blocked", map[string]string{"propagate.hnc.x-k8s.io/all": "true"})
481+
AddToHNCConfig(ctx, api.RBACGroup, api.RoleKind, api.Propagate)
482+
483+
// The object should not be propagated even though it uses the `all` annotation
484+
Consistently(HasObject(ctx, "roles", barName, "role-with-labels-blocked")).Should(BeFalse())
485+
})
486+
470487
It("should be removed if the hierarchy changes", func() {
471488
SetParent(ctx, barName, fooName)
472489
SetParent(ctx, bazName, barName)

internal/selectors/selectors.go

+6-16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"k8s.io/apimachinery/pkg/util/validation"
1414

1515
api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
16+
"sigs.k8s.io/hierarchical-namespaces/internal/config"
1617
)
1718

1819
// ShouldPropagate returns true if the given object should be propagated
@@ -43,8 +44,10 @@ func ShouldPropagate(inst *unstructured.Unstructured, nsLabels labels.Set, mode
4344
if none, err := GetNoneSelector(inst); err != nil || none {
4445
return false, err
4546
}
46-
if all, err := GetAllSelector(inst); err != nil || all {
47-
return true, err
47+
if all, err := GetAllSelector(inst); err != nil {
48+
return false, err
49+
} else if all {
50+
propIfNotExcluded = true
4851
}
4952
if excluded, err := isExcluded(inst); excluded {
5053
return false, err
@@ -197,19 +200,6 @@ func GetAllSelector(inst *unstructured.Unstructured) (bool, error) {
197200
// cmExclusionsByName are known (istio and kube-root) CA configmap which are excluded from propagation
198201
var cmExclusionsByName = []string{"istio-ca-root-cert", "kube-root-ca.crt"}
199202

200-
// A label as a key, value pair, used to exclude resources matching this label (both key and value).
201-
type ExclusionByLabelsSpec struct {
202-
Key string
203-
Value string
204-
}
205-
206-
// ExclusionByLabelsSpec are known label key-value pairs which are excluded from propagation. Right
207-
// now only used to exclude resources created by Rancher, see "System Tools > Remove"
208-
// (https://rancher.com/docs/rancher/v2.6/en/system-tools/#remove)
209-
var exclusionByLabels = []ExclusionByLabelsSpec{
210-
{Key: "cattle.io/creator", Value: "norman"},
211-
}
212-
213203
// A annotation as a key, value pair, used to exclude resources matching this annotation
214204
type ExclusionByAnnotationsSpec struct {
215205
Key string
@@ -246,7 +236,7 @@ func isExcluded(inst *unstructured.Unstructured) (bool, error) {
246236
}
247237

248238
// exclusion by labels
249-
for _, res := range exclusionByLabels {
239+
for _, res := range config.NoPropagationLabels {
250240
gotLabelValue, ok := inst.GetLabels()[res.Key]
251241
// check for presence has to be explicit, as empty label values are allowed and a
252242
// nonexisting key in the `labels` map will also return an empty string ("") - potentially

0 commit comments

Comments
 (0)