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

Commit bdee4bd

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 168dd7e commit bdee4bd

File tree

7 files changed

+92
-40
lines changed

7 files changed

+92
-40
lines changed

cmd/manager/main.go

Lines changed: 45 additions & 22 deletions
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"
@@ -55,28 +56,29 @@ var (
5556
)
5657

5758
var (
58-
probeAddr string
59-
metricsAddr string
60-
enableStackdriver bool
61-
maxReconciles int
62-
enableLeaderElection bool
63-
leaderElectionId string
64-
noWebhooks bool
65-
debugLogs bool
66-
testLog bool
67-
internalCert bool
68-
qps int
69-
webhookServerPort int
70-
restartOnSecretRefresh bool
71-
unpropagatedAnnotations arrayArg
72-
excludedNamespaces arrayArg
73-
managedNamespaceLabels arrayArg
74-
managedNamespaceAnnots arrayArg
75-
includedNamespacesRegex string
76-
webhooksOnly bool
77-
enableHRQ bool
78-
hncNamespace string
79-
hrqSyncInterval time.Duration
59+
probeAddr string
60+
metricsAddr string
61+
enableStackdriver bool
62+
maxReconciles int
63+
enableLeaderElection bool
64+
leaderElectionId string
65+
noWebhooks bool
66+
debugLogs bool
67+
testLog bool
68+
internalCert bool
69+
qps int
70+
webhookServerPort int
71+
restartOnSecretRefresh bool
72+
unpropagatedAnnotations arrayArg
73+
excludedNamespaces arrayArg
74+
managedNamespaceLabels arrayArg
75+
managedNamespaceAnnots arrayArg
76+
excludeResourcesWithLabel arrayArg
77+
includedNamespacesRegex string
78+
webhooksOnly bool
79+
enableHRQ bool
80+
hncNamespace string
81+
hrqSyncInterval time.Duration
8082
)
8183

8284
// init preloads some global vars before main() starts. Since this is the top-level module, I'm not
@@ -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(&excludeResourcesWithLabel, "exclude-objects-with-label", "An annotation specified as key=val that, if present, will cause HNC to skip objects that match this label. May be specified multiple times, with each instance 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 excludeResourcesWithLabel {
169+
keyVal := strings.Split(label, "=")
170+
if len(keyVal) != 2 {
171+
setupLog.Info(fmt.Sprintf("--exclude-objects-with-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("--exclude-objects-with-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.ExclusionByLabels = append(config.ExclusionByLabels, config.ExclusionByLabelsSpec{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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ spec:
4949
- "--excluded-namespace=kube-public"
5050
- "--excluded-namespace=hnc-system"
5151
- "--excluded-namespace=kube-node-lease"
52+
- "--exclude-objects-with-label=cattle.io/creator=norman"
5253
ports:
5354
- containerPort: 9443
5455
name: webhook-server

docs/user-guide/concepts.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,10 @@ objects from being propagated by HNC.
378378
auto-created in new namespaces by Istio and Kubernetes respectively
379379
* Any objects with the label
380380
`cattle.io/creator:norman`, which are [inserted by Rancher to support
381-
Projects](https://rancher.com/docs/rancher/v2.6/en/system-tools/#remove))
381+
Projects](https://rancher.com/docs/rancher/v2.6/en/system-tools/#remove)).
382+
Can be disabled by removing the default command line argument on the manager
383+
`--exclude-objects-with-label=cattle.io/creator=norman`. Refer to [How-to:
384+
Modify command-line arguments](how-to.md#modify-command-line-arguments) for more details.
382385
* *HNC v1.1+:* Secrets with type `helm.sh/release.v1`, which is auto-created in
383386
the namespaces where their respective Helm releases are deployed to.
384387

docs/user-guide/how-to.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,3 +956,10 @@ Interesting parameters include:
956956
load on your metrics database (through increased metric cardinality) and also
957957
by increasing how carefully you need to guard your metrics against
958958
unauthorized viewers.
959+
* `--exclude-objects-with-label`: present by default with label
960+
`cattle.io/creator=norman` in order to exclude objects created by Rancher
961+
(refer to [Concepts: built in exceptions](concepts.md#built-in-exceptions)
962+
for more information).
963+
This argument may be specified multiple times, with each parameter representing
964+
a pair of key and value that represent a label that should exclude an object from
965+
propagation. Must have the `key=val` format.

internal/config/default_config.go

Lines changed: 11 additions & 0 deletions
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+
// ExclusionByLabelsSpec 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 ExclusionByLabelsSpec struct {
15+
Key string
16+
Value string
17+
}
18+
19+
// ExclusionByLabels is a configuration slice that contains all ExclusionByLabelSpec labels that should
20+
// cause objects to be ignored from propagation.
21+
var ExclusionByLabels []ExclusionByLabelsSpec

internal/objects/reconciler_test.go

Lines changed: 18 additions & 1 deletion
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.ExclusionByLabels = append(config.ExclusionByLabels, config.ExclusionByLabelsSpec{Key: "cattle.io/creator", Value: "norman"})
452+
config.ExclusionByLabels = append(config.ExclusionByLabels, config.ExclusionByLabelsSpec{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.ExclusionByLabels = append(config.ExclusionByLabels, config.ExclusionByLabelsSpec{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 first one should not propagate, everything else should
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

Lines changed: 6 additions & 16 deletions
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.ExclusionByLabels {
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)