1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-30 19:35:06 +00:00

finish implementing global anchor

Signed-off-by: Maxim Goncharenko <goncharenko.maxim@apriorit.com>
This commit is contained in:
Maxim Goncharenko 2021-08-25 16:33:57 +03:00
parent d928f97795
commit 5d177d5d85
11 changed files with 37 additions and 67 deletions

View file

@ -94,7 +94,7 @@ func RemoveAnchor(key string) (string, string) {
return key[1 : len(key)-1], key[0:1]
}
if IsExistenceAnchor(key) || IsAddingAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
if IsExistenceAnchor(key) || IsAddingAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) || IsGlobalAnchor(key) {
return key[2 : len(key)-1], key[0:2]
}

View file

@ -18,10 +18,7 @@ func IsConditionalAnchorError(msg string) bool {
// IsGlobalAnchorError checks if error message has conditional anchor error string
func IsGlobalAnchorError(msg string) bool {
if strings.Contains(msg, GlobalAnchorErrMsg) {
return true
}
return false
return strings.Contains(msg, GlobalAnchorErrMsg)
}
// NewConditionalAnchorError returns a new instance of ConditionalAnchorError
@ -34,26 +31,20 @@ func NewConditionalAnchorError(msg string) ValidateAnchorError {
// IsConditionAnchorError ...
func (e ValidateAnchorError) IsConditionAnchorError() bool {
if e.Err == ConditionalAnchorErr {
return true
}
return false
return e.Err == ConditionalAnchorErr
}
// NewGlobalAnchorError returns a new instance of GlobalAnchorError
func NewGlobalAnchorError(msg string) ValidateAnchorError {
return ValidateAnchorError{
Err: GlobalAnchorErr,
Message: fmt.Sprintf("%s: %s", ConditionalAnchorErrMsg, msg),
Message: fmt.Sprintf("%s: %s", GlobalAnchorErrMsg, msg),
}
}
// IsConditionAnchorError ...
func (e ValidateAnchorError) IsGlobalAnchorError() bool {
if e.Err == GlobalAnchorErr {
return true
}
return false
return e.Err == GlobalAnchorErr
}
// IsNil ...

View file

@ -85,7 +85,16 @@ func ProcessStrategicMergePatch(ruleName string, overlay interface{}, resource u
func strategicMergePatch(logger logr.Logger, base, overlay string) ([]byte, error) {
preprocessedYaml, err := preProcessStrategicMergePatch(logger, overlay, base)
if err != nil {
return []byte{}, fmt.Errorf("failed to preProcess rule: %+v", err)
_, isConditionError := err.(ConditionError)
_, isGlobalConditionError := err.(GlobalConditionError)
if isConditionError || isGlobalConditionError {
if err = preprocessedYaml.UnmarshalJSON([]byte(`{}`)); err != nil {
return []byte{}, err
}
} else {
return []byte{}, fmt.Errorf("failed to preProcess rule: %+v", err)
}
}
f := patchstrategicmerge.Filter{
@ -98,14 +107,11 @@ func strategicMergePatch(logger logr.Logger, base, overlay string) ([]byte, erro
return baseObj.Bytes(), err
}
var counter = 1
func preProcessStrategicMergePatch(logger logr.Logger, pattern, resource string) (*yaml.RNode, error) {
patternNode := yaml.MustParse(pattern)
resourceNode := yaml.MustParse(resource)
err := preProcessPattern(logger, patternNode, resourceNode)
counter += 1
return patternNode, err
}

View file

@ -422,55 +422,28 @@ func deleteAnchorsInMap(node *yaml.RNode) (bool, error) {
return false, err
}
needToDelete := true
// Go further through the map elements.
for _, field := range fields {
patternValue := node.Field(field).Value
var wasEmpty bool
var isSequence bool
if patternValue.YNode().Kind == yaml.SequenceNode {
isSequence = true
elements, err := patternValue.Elements()
if err != nil {
return false, err
}
if len(elements) == 0 {
wasEmpty = true
}
}
ok, err := deleteAnchors(node.Field(field).Value)
if err != nil {
return false, err
}
// If we have at least one element without anchor,
// then we don't need to delete this element.
if !ok {
return false, nil
}
if isSequence {
patternValue := node.Field(field).Value
elements, err := patternValue.Elements()
if ok {
err = node.PipeE(yaml.Clear(field))
if err != nil {
return false, err
}
if len(elements) == 0 && !wasEmpty {
// List became empty after deleting anchors,
// delete it
err = node.PipeE(yaml.Clear(field))
if err != nil {
return false, err
}
}
} else {
// If we have at least one element without anchor,
// then we don't need to delete this element.
needToDelete = false
}
}
return true, nil
return needToDelete, nil
}
func deleteAnchorsInList(node *yaml.RNode) (bool, error) {
@ -479,6 +452,8 @@ func deleteAnchorsInList(node *yaml.RNode) (bool, error) {
return false, err
}
wasEmpty := len(elements) == 0
for i, element := range elements {
if hasAnchors(element) {
deleteListElement(node, i)
@ -490,9 +465,6 @@ func deleteAnchorsInList(node *yaml.RNode) (bool, error) {
if err != nil {
return false, err
}
if err != nil {
return false, err
}
if ok {
deleteListElement(node, i)
}
@ -503,7 +475,7 @@ func deleteAnchorsInList(node *yaml.RNode) (bool, error) {
if err != nil {
return false, err
}
if len(elements) == 0 {
if len(elements) == 0 && !wasEmpty {
return true, nil
}

View file

@ -573,8 +573,7 @@ func Test_preProcessStrategicMergePatch_multipleAnchors(t *testing.T) {
"metadata": {
"annotations": {
"annotation2": "atest2"
},
"labels": {}
}
},
"spec": {
"containers": [

View file

@ -1398,7 +1398,7 @@ func TestConditionalAnchorWithMultiplePatterns(t *testing.T) {
name: "check global anchor",
pattern: []byte(`{"spec": {"containers": [{"name": "*","<(image)": "*:latest","imagePullPolicy": "!Always"}]}}`),
resource: []byte(`{"spec": {"containers": [{"name": "nginx","image": "nginx", "imagePullPolicy": "Always"}]}}`),
nilErr: false,
nilErr: true,
},
{
name: "test-4",

View file

@ -31,7 +31,7 @@ func (v *Validate) Validate() (string, error) {
}
if rule.Pattern != nil {
if path, err := common.ValidatePattern(rule.Pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor}); err != nil {
if path, err := common.ValidatePattern(rule.Pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor, commonAnchors.IsGlobalAnchor}); err != nil {
return fmt.Sprintf("pattern.%s", path), err
}
}
@ -42,7 +42,7 @@ func (v *Validate) Validate() (string, error) {
return "anyPattern", fmt.Errorf("failed to deserialize anyPattern, expect array: %v", err)
}
for i, pattern := range anyPattern {
if path, err := common.ValidatePattern(pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor}); err != nil {
if path, err := common.ValidatePattern(pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor, commonAnchors.IsGlobalAnchor}); err != nil {
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
}
}

View file

@ -21,7 +21,7 @@ spec:
+(cluster-autoscaler.kubernetes.io/safe-to-evict): "true"
spec:
volumes:
- (emptyDir): {}
- <(emptyDir): {}
- name: annotate-host-path
match:
resources:
@ -34,5 +34,5 @@ spec:
+(cluster-autoscaler.kubernetes.io/safe-to-evict): "true"
spec:
volumes:
- (hostPath):
path: "*"
- hostPath:
<(path): "*"

View file

@ -2,6 +2,7 @@ apiVersion: v1
kind: Pod
metadata:
name: pod-with-default-volume
creationTimestamp: "2020-09-21T12:56:35Z"
spec:
containers:
- image: k8s.gcr.io/test-webserver

View file

@ -2,6 +2,7 @@ apiVersion: v1
kind: Pod
metadata:
name: pod-with-default-volume
creationTimestamp: "2020-09-21T12:56:35Z"
spec:
containers:
- image: k8s.gcr.io/test-webserver

View file

@ -4,7 +4,7 @@ input:
resource: test/resources/pod-with-default-volume.yaml
expected:
mutation:
patchedresource: test/resources/pod-with-default-volume.yaml
patchedresource: test/output/pod-with-default-volume.yaml
policyresponse:
policy:
namespace: ''