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

Commit e297652

Browse files
authored
Merge pull request #89 from santinoncs/included-namespaces
Add --include-namespaces-regex features
2 parents de12632 + 77c3d14 commit e297652

20 files changed

+106
-33
lines changed

cmd/manager/main.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var (
6767
restartOnSecretRefresh bool
6868
unpropagatedAnnotations arrayArg
6969
excludedNamespaces arrayArg
70+
includedNamespacesRegex string
7071
)
7172

7273
func init() {
@@ -98,14 +99,13 @@ func main() {
9899
flag.IntVar(&webhookServerPort, "webhook-server-port", 443, "The port that the webhook server serves at.")
99100
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.")
100101
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.")
102+
flag.StringVar(&includedNamespacesRegex, "included-namespace-regex", ".*", "Namespace regular expression. Namespaces that match this regexp will be included and handle by HNC. As it is a regex, this parameter cannot be specified multiple times. Implicit wrapping of the expression \"^...$\" is done here")
101103
flag.BoolVar(&restartOnSecretRefresh, "cert-restart-on-secret-refresh", false, "Kills the process when secrets are refreshed so that the pod can be restarted (secrets take up to 60s to be updated by running pods)")
102104
flag.Parse()
103105
// Assign the array args to the configuration variables after the args are parsed.
104106
config.UnpropagatedAnnotations = unpropagatedAnnotations
105-
config.ExcludedNamespaces = make(map[string]bool)
106-
for _, exn := range excludedNamespaces {
107-
config.ExcludedNamespaces[exn] = true
108-
}
107+
108+
config.SetNamespaces(includedNamespacesRegex, excludedNamespaces...)
109109

110110
// Enable OpenCensus exporters to export metrics
111111
// to Stackdriver Monitoring.

hack/tools.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
//+build tools
1+
//go:build tools
2+
// +build tools
3+
24
//
35
// This is used to ensure that controller-gen is included in the /vendor directory. See
46
// https://stackoverflow.com/questions/52428230/how-do-go-modules-work-with-installable-commands.

internal/config/default_config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package config
22

3+
import "regexp"
4+
35
// UnpropgatedAnnotations is a list of annotations on objects that should _not_ be propagated by HNC.
46
// Much like HNC itself, other systems (such as GKE Config Sync) use annotations to "claim" an
57
// object - such as deleting objects it doesn't recognize. By removing these annotations on
@@ -14,4 +16,5 @@ var UnpropagatedAnnotations []string
1416
//
1517
// This value is controlled by the --excluded-namespace command line, which may
1618
// be set multiple times.
17-
var ExcludedNamespaces map[string]bool
19+
var excludedNamespaces map[string]bool
20+
var includedNamespacesRegex *regexp.Regexp

internal/config/namespace.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package config
2+
3+
import (
4+
"regexp"
5+
)
6+
7+
func SetNamespaces(regex string, excluded ...string) {
8+
9+
if regex == "" {
10+
regex = ".*"
11+
}
12+
13+
includedNamespacesRegex = regexp.MustCompile("^" + regex + "$")
14+
15+
excludedNamespaces = make(map[string]bool)
16+
for _, exn := range excluded {
17+
excludedNamespaces[exn] = true
18+
}
19+
20+
}
21+
22+
func IsNamespaceIncluded(name string) bool {
23+
24+
if excludedNamespaces[name] {
25+
return false
26+
}
27+
28+
return includedNamespacesRegex.MatchString(name)
29+
30+
}

internal/config/namespace_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package config
2+
3+
import (
4+
. "github.com/onsi/gomega"
5+
"testing"
6+
)
7+
8+
func TestIsNamespaceIncluded(t *testing.T) {
9+
10+
tests := []struct {
11+
name string
12+
regex string
13+
excludeNamespaces []string
14+
expect bool
15+
}{
16+
{name: "foobar", regex: "foo.*", excludeNamespaces: []string{"bar"}, expect: true},
17+
{name: "bar", regex: "foo-.*", excludeNamespaces: []string{"bar"}, expect: false},
18+
{name: "bar", regex: ".*", excludeNamespaces: []string{"bar"}, expect: false},
19+
{name: "foo", regex: ".*", excludeNamespaces: []string{"bar"}, expect: true},
20+
{name: "foo", regex: ".*", excludeNamespaces: []string{"bar", "foo"}, expect: false},
21+
}
22+
23+
for _, tc := range tests {
24+
t.Run(tc.name, func(t *testing.T) {
25+
g := NewWithT(t)
26+
27+
// Test
28+
SetNamespaces(tc.regex, tc.excludeNamespaces...)
29+
isIncluded := IsNamespaceIncluded(tc.name)
30+
31+
// Report
32+
g.Expect(isIncluded).Should(Equal(tc.expect))
33+
})
34+
}
35+
36+
}

internal/mutators/namespace.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ func (m *Namespace) Handle(ctx context.Context, req admission.Request) admission
5252
// Currently, we only add `included-namespace` label to non-excluded namespaces
5353
// if the label is missing.
5454
func (m *Namespace) handle(log logr.Logger, ns *corev1.Namespace) {
55-
// Early exit if the namespace is excluded.
56-
if config.ExcludedNamespaces[ns.Name] {
55+
56+
if !config.IsNamespaceIncluded(ns.Name) {
5757
return
5858
}
5959

internal/mutators/namespace_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func TestMutateNamespaceIncludedLabel(t *testing.T) {
1515
m := &Namespace{}
1616
l := zap.New()
17-
config.ExcludedNamespaces = map[string]bool{"excluded": true}
17+
config.SetNamespaces("", "excluded")
1818

1919
tests := []struct {
2020
name string

internal/reconcilers/anchor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (r *AnchorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
7575

7676
// Always delete anchor (and any other HNC CRs) in the excluded namespaces and
7777
// early exit.
78-
if config.ExcludedNamespaces[pnm] {
78+
if !config.IsNamespaceIncluded(pnm) {
7979
// Since the anchors in the excluded namespaces are never synced by HNC,
8080
// there are no finalizers on the anchors that we can delete them without
8181
// removing the finalizers first.
@@ -87,7 +87,7 @@ func (r *AnchorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
8787
// namespace that should not be created as a subnamespace, but the webhook has
8888
// been bypassed and the anchor has been successfully created. Forbidden
8989
// anchors won't have finalizers.
90-
if config.ExcludedNamespaces[nm] {
90+
if !config.IsNamespaceIncluded(nm) {
9191
inst.Status.State = api.Forbidden
9292
return ctrl.Result{}, r.writeInstance(ctx, log, inst)
9393
}

internal/reconcilers/anchor_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var _ = Describe("Anchor", func() {
2222
BeforeEach(func() {
2323
fooName = createNS(ctx, "foo")
2424
barName = createNSName("bar")
25-
config.ExcludedNamespaces = nil
25+
config.SetNamespaces("")
2626
})
2727

2828
It("should create an subnamespace and update the hierarchy according to the anchor", func() {
@@ -52,14 +52,14 @@ var _ = Describe("Anchor", func() {
5252
})
5353

5454
It("should remove the anchor in an excluded namespace", func() {
55-
config.ExcludedNamespaces = map[string]bool{"kube-system": true}
55+
config.SetNamespaces("", "kube-system")
5656
kube_system_anchor_bar := newAnchor(barName, "kube-system")
5757
updateAnchor(ctx, kube_system_anchor_bar)
5858
Eventually(canGetAnchor(ctx, barName, "kube-system")).Should(Equal(false))
5959
})
6060

6161
It("should set the anchor.status.state to Forbidden if the subnamespace is an excluded namespace", func() {
62-
config.ExcludedNamespaces = map[string]bool{"kube-system": true}
62+
config.SetNamespaces("", "kube-system")
6363
foo_anchor_kube_system := newAnchor("kube-system", fooName)
6464
updateAnchor(ctx, foo_anchor_kube_system)
6565
Eventually(getAnchorState(ctx, fooName, "kube-system")).Should(Equal(api.Forbidden))

internal/reconcilers/hierarchy_config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ func (r *HierarchyConfigReconciler) Reconcile(ctx context.Context, req ctrl.Requ
8888
ns := req.NamespacedName.Namespace
8989
log := loggerWithRID(r.Log).WithValues("ns", ns)
9090

91-
// Early exit if it's an excluded namespace.
92-
if config.ExcludedNamespaces[ns] {
91+
// Early exit if it's an excluded namespace
92+
if !config.IsNamespaceIncluded(ns) {
9393
return ctrl.Result{}, r.handleExcludedNamespace(ctx, log, ns)
9494
}
9595

@@ -418,7 +418,7 @@ func (r *HierarchyConfigReconciler) syncParent(log logr.Logger, inst *api.Hierar
418418

419419
// Sync this namespace with its current parent.
420420
curParent := r.Forest.Get(inst.Spec.Parent)
421-
if config.ExcludedNamespaces[inst.Spec.Parent] {
421+
if !config.IsNamespaceIncluded(inst.Spec.Parent) {
422422
log.Info("Setting ConditionActivitiesHalted: excluded namespace set as parent", "parent", inst.Spec.Parent)
423423
ns.SetCondition(api.ConditionActivitiesHalted, api.ReasonIllegalParent, fmt.Sprintf("Parent %q is an excluded namespace", inst.Spec.Parent))
424424
} else if curParent != nil && !curParent.Exists() {

0 commit comments

Comments
 (0)