mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-08 10:04:25 +00:00
add annotation wildcard support
This commit is contained in:
parent
76b6974fc2
commit
59ba4fe3ac
3 changed files with 53 additions and 16 deletions
pkg
|
@ -201,15 +201,15 @@ type ResourceDescription struct {
|
|||
// +optional
|
||||
Namespaces []string `json:"namespaces,omitempty" yaml:"namespaces,omitempty"`
|
||||
|
||||
// Annotations is a map of annotations (string key-value pairs). Annotation values
|
||||
// supports wildcard characters "*" (matches zero or many characters) and
|
||||
// "?" (at least one character).
|
||||
// Annotations is a map of annotations (key-value pairs of type string). Annotation keys
|
||||
// and values support the wildcard characters "*" (matches zero or many characters) and
|
||||
// "?" (matches at least one character).
|
||||
// +optional
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
|
||||
// Selector is a label selector. Label keys and values in `matchLabels` support the wildcard
|
||||
// characters `*` (matches zero or many characters) and `?` (matches one character).
|
||||
// This feature allows writing label selectors like ["storage.k8s.io/*": "*"]. Note that
|
||||
// Wildcards allows writing label selectors like ["storage.k8s.io/*": "*"]. Note that
|
||||
// using ["*" : "*"] matches any key and value but does not match an empty label set.
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
|
|
|
@ -54,19 +54,29 @@ func checkNameSpace(namespaces []string, resourceNameSpace string) bool {
|
|||
}
|
||||
|
||||
func checkAnnotations(annotations map[string]string, resourceAnnotations map[string]string) bool {
|
||||
if len(annotations) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for k, v := range annotations {
|
||||
if len(resourceAnnotations) == 0 {
|
||||
return false
|
||||
match := false
|
||||
for k1, v1 := range resourceAnnotations {
|
||||
if wildcard.Match(k, k1) && wildcard.Match(v, v1) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if resourceAnnotations[k] != v {
|
||||
|
||||
if match == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) (bool, error) {
|
||||
replaceWildCardsInSelector(labelSelector, resourceLabels)
|
||||
replaceWildcardsInSelector(labelSelector, resourceLabels)
|
||||
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to build label selector")
|
||||
|
@ -80,13 +90,13 @@ func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[strin
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// replaceWildCardsInSelector replaces label selector keys containing
|
||||
// wildcard characters with matching keys from the resource labels.
|
||||
func replaceWildCardsInSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) {
|
||||
// replaceWildcardsInSelector replaces label selector keys and values containing
|
||||
// wildcard characters with matching keys and values from the resource labels.
|
||||
func replaceWildcardsInSelector(labelSelector *metav1.LabelSelector, resourceLabels map[string]string) {
|
||||
result := map[string]string{}
|
||||
for k, v := range labelSelector.MatchLabels {
|
||||
if containsWildCard(k) || containsWildCard(v) {
|
||||
matchK, matchV := expandWildCards(k, v, resourceLabels)
|
||||
if containsWildcards(k) || containsWildcards(v) {
|
||||
matchK, matchV := expandWildcards(k, v, resourceLabels)
|
||||
result[matchK] = matchV
|
||||
} else {
|
||||
result[k] = v
|
||||
|
@ -96,11 +106,11 @@ func replaceWildCardsInSelector(labelSelector *metav1.LabelSelector, resourceLab
|
|||
labelSelector.MatchLabels = result
|
||||
}
|
||||
|
||||
func containsWildCard(s string) bool {
|
||||
func containsWildcards(s string) bool {
|
||||
return strings.Contains(s, "*") || strings.Contains(s, "?")
|
||||
}
|
||||
|
||||
func expandWildCards(k, v string, labels map[string]string) (key string, val string) {
|
||||
func expandWildcards(k, v string, labels map[string]string) (key string, val string) {
|
||||
for k1, v1 := range labels {
|
||||
if wildcard.Match(k, k1) {
|
||||
if wildcard.Match(v, v1) {
|
||||
|
@ -114,10 +124,11 @@ func expandWildCards(k, v string, labels map[string]string) (key string, val str
|
|||
return k, v
|
||||
}
|
||||
|
||||
// replaceWildCardChars will replace '*' and '?' characters which are not
|
||||
// supported by Kubernetes with a '0'.
|
||||
func replaceWildCardChars(s string) string {
|
||||
s = strings.Replace(s, "*", "0", -1)
|
||||
s = strings.Replace(s, "?", "0", -1)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
|
@ -526,3 +526,29 @@ func testSelector(t *testing.T, s *metav1.LabelSelector, l map[string]string, ma
|
|||
t.Errorf("select %v -> labels %v: expected %v received %v", s.MatchLabels, l, match, res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWildCardAnnotation(t *testing.T) {
|
||||
|
||||
// test single annotation values
|
||||
testAnnotationMatch(t, map[string]string{}, map[string]string{}, true)
|
||||
testAnnotationMatch(t, map[string]string{"test/*": "*"}, map[string]string{}, false)
|
||||
testAnnotationMatch(t, map[string]string{"test/*": "*"}, map[string]string{"tes1/test": "*"}, false)
|
||||
testAnnotationMatch(t, map[string]string{"test/*": "*"}, map[string]string{"test/test": "*"}, true)
|
||||
testAnnotationMatch(t, map[string]string{"test/*": "*"}, map[string]string{"test/bar": "foo"}, true)
|
||||
testAnnotationMatch(t, map[string]string{"test/b*": "*"}, map[string]string{"test/bar": "foo"}, true)
|
||||
|
||||
// test multiple annotation values
|
||||
testAnnotationMatch(t, map[string]string{"test/b*": "*", "test2/*": "*"},
|
||||
map[string]string{"test/bar": "foo"}, false)
|
||||
testAnnotationMatch(t, map[string]string{"test/b*": "*", "test2/*": "*"},
|
||||
map[string]string{"test/bar": "foo", "test2/123": "bar"}, true)
|
||||
testAnnotationMatch(t, map[string]string{"test/b*": "*", "test2/*": "*"},
|
||||
map[string]string{"test/bar": "foo", "test2/123": "bar", "test3/123": "bar2"}, true)
|
||||
}
|
||||
|
||||
func testAnnotationMatch(t *testing.T, policy map[string]string, resource map[string]string, match bool) {
|
||||
res := checkAnnotations(policy, resource)
|
||||
if res != match {
|
||||
t.Errorf("annotations %v -> labels %v: expected %v received %v", policy, resource, match, res)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue