mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
adding support for multiple names in match and exclude blocks (#2010)
* add names in rd struct Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * added checking logic Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * updated yamls Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * wip: fix empty set problem Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * working with exclude Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * fixing name and names Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * added error if both name and names are specified Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * added tests Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * changed empty set logic, fixed whitespaces and comments Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com> * fix match and exclude bug Signed-off-by: RinkiyaKeDad <arshsharma461@gmail.com>
This commit is contained in:
parent
8556cf6c91
commit
fbc80cdfae
9 changed files with 3675 additions and 978 deletions
File diff suppressed because it is too large
Load diff
|
@ -146,6 +146,13 @@ spec:
|
|||
supports wildcard characters "*" (matches zero or
|
||||
many characters) and "?" (at least one character).
|
||||
type: string
|
||||
names:
|
||||
description: Names are the names of the resources. Each
|
||||
name supports wildcard characters "*" (matches zero
|
||||
or many characters) and "?" (at least one character).
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector
|
||||
for the resource namespace. Label keys and values
|
||||
|
@ -382,6 +389,13 @@ spec:
|
|||
supports wildcard characters "*" (matches zero or
|
||||
many characters) and "?" (at least one character).
|
||||
type: string
|
||||
names:
|
||||
description: Names are the names of the resources. Each
|
||||
name supports wildcard characters "*" (matches zero
|
||||
or many characters) and "?" (at least one character).
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector
|
||||
for the resource namespace. Label keys and values
|
||||
|
|
|
@ -147,6 +147,13 @@ spec:
|
|||
supports wildcard characters "*" (matches zero or
|
||||
many characters) and "?" (at least one character).
|
||||
type: string
|
||||
names:
|
||||
description: Names are the names of the resources. Each
|
||||
name supports wildcard characters "*" (matches zero
|
||||
or many characters) and "?" (at least one character).
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector
|
||||
for the resource namespace. Label keys and values
|
||||
|
@ -383,6 +390,13 @@ spec:
|
|||
supports wildcard characters "*" (matches zero or
|
||||
many characters) and "?" (at least one character).
|
||||
type: string
|
||||
names:
|
||||
description: Names are the names of the resources. Each
|
||||
name supports wildcard characters "*" (matches zero
|
||||
or many characters) and "?" (at least one character).
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector
|
||||
for the resource namespace. Label keys and values
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -263,6 +263,11 @@ type ResourceDescription struct {
|
|||
// +optional
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Names are the names of the resources. Each name supports wildcard characters
|
||||
// "*" (matches zero or many characters) and "?" (at least one character).
|
||||
// +optional
|
||||
Names []string `json:"names,omitempty" yaml:"names,omitempty"`
|
||||
|
||||
// Namespaces is a list of namespaces names. Each name supports wildcard characters
|
||||
// "*" (matches zero or many characters) and "?" (at least one character).
|
||||
// +optional
|
||||
|
|
|
@ -135,6 +135,19 @@ func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription,
|
|||
}
|
||||
}
|
||||
|
||||
if len(conditionBlock.Names) > 0 {
|
||||
noneMatch := true
|
||||
for i := range conditionBlock.Names {
|
||||
if checkName(conditionBlock.Names[i], resource.GetName()) {
|
||||
noneMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if noneMatch {
|
||||
errs = append(errs, fmt.Errorf("none of the names match"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(conditionBlock.Namespaces) > 0 {
|
||||
if !checkNameSpace(conditionBlock.Namespaces, resource) {
|
||||
errs = append(errs, fmt.Errorf("namespace does not match"))
|
||||
|
|
|
@ -41,6 +41,30 @@ func TestMatchesResourceDescription(t *testing.T) {
|
|||
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"name":"hello-world"},"clusterRoles":["system:node"]},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
|
||||
areErrorsExpected: false,
|
||||
},
|
||||
{
|
||||
Description: "Should fail since resource does not match because of names field",
|
||||
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
|
||||
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"],"names": ["dev-*"]},"clusterRoles":["system:node"]},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
|
||||
areErrorsExpected: true,
|
||||
},
|
||||
{
|
||||
Description: "Should pass since resource matches a name in the names field",
|
||||
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
|
||||
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"],"names": ["dev-*","hello-world"]},"clusterRoles":["system:node"]},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
|
||||
areErrorsExpected: false,
|
||||
},
|
||||
{
|
||||
Description: "Should fail since resource gets excluded because of the names field",
|
||||
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"hello-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
|
||||
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"names": ["dev-*","hello-*"]}},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
|
||||
areErrorsExpected: true,
|
||||
},
|
||||
{
|
||||
Description: "Should pass since resource does not get excluded because of the names field",
|
||||
Resource: []byte(`{"apiVersion":"v1","kind":"Pod","metadata":{"name":"bye-world","labels":{"name":"hello-world"}},"spec":{"containers":[{"name":"hello-world","image":"hello-world","ports":[{"containerPort":81}],"resources":{"limits":{"memory":"30Mi","cpu":"0.2"},"requests":{"memory":"20Mi","cpu":"0.1"}}}]}}`),
|
||||
Policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"hello-world-policy"},"spec":{"background":false,"rules":[{"name":"hello-world-policy","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"names": ["dev-*","hello-*"]}},"mutate":{"overlay":{"spec":{"containers":[{"(image)":"*","imagePullPolicy":"IfNotPresent"}]}}}}]}}`),
|
||||
areErrorsExpected: false,
|
||||
},
|
||||
{
|
||||
Description: "Should fail since resource does not match policy",
|
||||
AdmissionInfo: kyverno.RequestInfo{
|
||||
|
|
|
@ -177,6 +177,7 @@ func Validate(policy *kyverno.ClusterPolicy, client *dclient.Client, mock bool,
|
|||
|
||||
// doMatchAndExcludeConflict checks if the resultant
|
||||
// of match and exclude block is not an empty set
|
||||
// returns true if it is an empty set
|
||||
func doMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
||||
|
||||
if reflect.DeepEqual(rule.ExcludeResources, kyverno.ExcludeResources{}) {
|
||||
|
@ -268,6 +269,28 @@ func doMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
|||
}
|
||||
}
|
||||
|
||||
if len(rule.ExcludeResources.ResourceDescription.Names) > 0 {
|
||||
excludeSlice := rule.ExcludeResources.ResourceDescription.Names
|
||||
matchSlice := rule.MatchResources.ResourceDescription.Names
|
||||
|
||||
// if exclude block has something and match doesn't it means we
|
||||
// have a non empty set
|
||||
if len(rule.MatchResources.ResourceDescription.Names) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// if *any* name in match and exclude conflicts
|
||||
// we want user to fix that
|
||||
for _, matchName := range matchSlice {
|
||||
for _, excludeName := range excludeSlice {
|
||||
if wildcard.Match(excludeName, matchName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if len(excludeNamespaces) > 0 {
|
||||
if len(rule.MatchResources.ResourceDescription.Namespaces) == 0 {
|
||||
return false
|
||||
|
@ -715,6 +738,10 @@ func validateMatchedResourceDescription(rd kyverno.ResourceDescription) (string,
|
|||
return "", fmt.Errorf("match resources not specified")
|
||||
}
|
||||
|
||||
if rd.Name != "" && len(rd.Names) > 0 {
|
||||
return "", fmt.Errorf("both name and names can not be specified together")
|
||||
}
|
||||
|
||||
if err := validateResourceDescription(rd); err != nil {
|
||||
return "match", err
|
||||
}
|
||||
|
@ -778,6 +805,11 @@ func validateExcludeResourceDescription(rd kyverno.ResourceDescription) (string,
|
|||
// exclude is not mandatory
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if rd.Name != "" && len(rd.Names) > 0 {
|
||||
return "", fmt.Errorf("both name and names can not be specified together")
|
||||
}
|
||||
|
||||
if err := validateResourceDescription(rd); err != nil {
|
||||
return "exclude", err
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue