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:
parent
d928f97795
commit
5d177d5d85
11 changed files with 37 additions and 67 deletions
|
@ -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]
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ...
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -573,8 +573,7 @@ func Test_preProcessStrategicMergePatch_multipleAnchors(t *testing.T) {
|
|||
"metadata": {
|
||||
"annotations": {
|
||||
"annotation2": "atest2"
|
||||
},
|
||||
"labels": {}
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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): "*"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: ''
|
||||
|
|
Loading…
Add table
Reference in a new issue