Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/mutation/match/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func namesMatch(match *Match, target *Matchable) (bool, error) {
return true, nil
}

return match.Name.Matches(target.Object.GetName()), nil
return match.Name.Matches(target.Object.GetName()) || match.Name.MatchesGenerateName(target.Object.GetGenerateName()), nil
}

func scopeMatch(match *Match, target *Matchable) (bool, error) {
Expand Down
207 changes: 207 additions & 0 deletions pkg/mutation/match/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -831,3 +831,210 @@ func TestApplyTo(t *testing.T) {
})
}
}

func makeObjectWithGenerateName(gvk schema.GroupVersionKind, namespace, name string, options ...func(*unstructured.Unstructured)) *unstructured.Unstructured {
obj := &unstructured.Unstructured{Object: make(map[string]interface{})}
obj.SetGroupVersionKind(gvk)
obj.SetNamespace(namespace)
obj.SetGenerateName(name)

for _, o := range options {
o(obj)
}
return obj
}

func Test_namesMatch(t *testing.T) {
type args struct {
match *Match
target *Matchable
}

tests := []struct {
name string
args args
want bool
wantErr bool
}{
{
name: "match name with wild card",
args: args{
match: &Match{
Name: "foo*",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObject(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo-bar"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: true,
wantErr: false,
},
{
name: "match generate name with wild card",
args: args{
match: &Match{
Name: "foo*",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo-bar-"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: true,
wantErr: false,
},
{
name: "match different name with wild card",
args: args{
match: &Match{
Name: "foo*",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObject(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: false,
wantErr: false,
},
{
name: "match different generate name with wild card",
args: args{
match: &Match{
Name: "foo*",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob-bar-"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: false,
wantErr: false,
},
{
name: "match whole name with generate name",
args: args{
match: &Match{
Name: "foo",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: false,
wantErr: false,
},
{
name: "match prefix wildcard with generate name",
args: args{
match: &Match{
Name: "*foo",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "foo"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: false,
wantErr: false,
},
{
name: "match later half of the name with wild card with generate name",
args: args{
match: &Match{
Name: "*-bar*",
Kinds: []Kinds{
{
Kinds: []string{"Pod"},
APIGroups: []string{"*"},
},
},
},
target: &Matchable{
Object: makeObjectWithGenerateName(schema.GroupVersionKind{Kind: "Pod", Group: "*"}, "my-ns", "fob-bar"),
Namespace: &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "my-ns",
},
},
},
},
want: true,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := namesMatch(tt.args.match, tt.args.target)
if (err != nil) != tt.wantErr {
t.Errorf("namesMatch() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("namesMatch() = %v, want %v", got, tt.want)
}
})
}
}
12 changes: 12 additions & 0 deletions pkg/wildcard/wildcard.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ func (w Wildcard) Matches(candidate string) bool {
return wStr == candidate
}
}

func (w Wildcard) MatchesGenerateName(candidate string) bool {
wStr := string(w)
switch {
case strings.HasPrefix(wStr, "*") && strings.HasSuffix(wStr, "*"):
return strings.Contains(candidate, strings.TrimSuffix(strings.TrimPrefix(wStr, "*"), "*"))
case strings.HasSuffix(wStr, "*"):
return strings.HasPrefix(candidate, strings.TrimSuffix(wStr, "*"))
default:
return false
}
}
98 changes: 97 additions & 1 deletion pkg/wildcard/wildcard_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package wildcard

import "testing"
import (
"testing"
)

func TestMatches(t *testing.T) {
tcs := []struct {
Expand Down Expand Up @@ -95,3 +97,97 @@ func TestMatches(t *testing.T) {
})
}
}

func TestWildcard_MatchesGenerateName(t *testing.T) {
tcs := []struct {
name string
w Wildcard
candidate string
matches bool
}{
{
name: "exact text match",
w: Wildcard("kube-system"),
candidate: "kube-system",
matches: false,
},
{
name: "no glob, wrong text",
w: Wildcard("kube-system"),
candidate: "gatekeeper-system",
matches: false,
},
{
name: "wildcard prefix match",
w: Wildcard("kube-*"),
candidate: "kube-system",
matches: true,
},
{
name: "wildcard prefix doesn't match",
w: Wildcard("kube-*"),
candidate: "gatekeeper-system",
matches: false,
},
{
name: "wildcard suffix match",
w: Wildcard("*-system"),
candidate: "kube-system",
matches: false,
},
{
name: "wildcard suffix doesn't match",
w: Wildcard("*-system"),
candidate: "kube-public",
matches: false,
},
{
name: "missing asterisk yields no wildcard support",
w: Wildcard("kube-"),
candidate: "kube-system",
matches: false,
},
{
name: "wildcard suffix and prefix match",
w: Wildcard("*-kube-*"),
candidate: "test-kube-test",
matches: true,
},
{
name: "no wildcard, only hypens at suffix and prefix",
w: Wildcard("-kube-"),
candidate: "test-kube-test",
matches: false,
},
{
name: "wild card at suffix and prefix, multiple hyphens",
w: Wildcard("*-kube-*"),
candidate: "test-dev-kube-dev-test",
matches: true,
},
{
name: "wild card at suffid and end, multiple hypens, no match",
w: Wildcard("*-kube-*"),
candidate: "my-kub-controller",
matches: false,
},
{
name: "wild card at suffix and prefix, multiple hyphens, no match",
w: Wildcard("*-kube-*"),
candidate: "my-controller-manager",
matches: false,
},
}

for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
if tc.w.MatchesGenerateName(tc.candidate) != tc.matches {
if tc.matches {
t.Errorf("Expected candidate '%v' to match wildcard '%v'", tc.candidate, tc.w)
} else {
t.Errorf("Candidate '%v' unexpectedly matched wildcard '%v'", tc.candidate, tc.w)
}
}
})
}
}