mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-08 10:04:25 +00:00
Merge branch '414_mutate_safe-to-evict_emptydir' into 413_known_ingress
This commit is contained in:
commit
38f1f3bbb9
11 changed files with 155 additions and 161 deletions
|
@ -1,21 +0,0 @@
|
|||
# MutatingWebhookConfiguration document which should be used when placing controller inside the cluster
|
||||
# This configuration is just an example. Webhook for in-cluster configuration is registered by controller (see webhooks/registration.go).
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
name: nirmata-kyverno-webhook-cfg
|
||||
labels:
|
||||
app: kyverno
|
||||
webhooks:
|
||||
- name: webhook.nirmata.kyverno
|
||||
clientConfig:
|
||||
service:
|
||||
name: kyverno-svc
|
||||
namespace: default
|
||||
path: "/mutate"
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- operations: [ "CREATE" ]
|
||||
resources: [ "*/*" ]
|
||||
apiGroups: [ "*" ]
|
||||
apiVersions: [ "*" ]
|
|
@ -1,7 +1,6 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
@ -52,8 +51,9 @@ func Mutate(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (r
|
|||
if rule.Mutation.Overlay != nil {
|
||||
var ruleResponse RuleResponse
|
||||
ruleResponse, patchedResource = processOverlay(rule, resource)
|
||||
if strings.Contains(ruleResponse.Message, "policy not applied") {
|
||||
if ruleResponse.Success == true && ruleResponse.Patches == nil {
|
||||
// overlay pattern does not match the resource conditions
|
||||
glog.Infof(ruleResponse.Message)
|
||||
continue
|
||||
}
|
||||
response.PolicyResponse.Rules = append(response.PolicyResponse.Rules, ruleResponse)
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
@ -17,10 +16,6 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
)
|
||||
|
||||
// conditionalFieldEmpty is the message to indicate the conditional key
|
||||
// is not present in the resource, the rule is skipped and is considered as successs
|
||||
const conditionalFieldEmpty = "resource field is not present"
|
||||
|
||||
// processOverlay processes validation patterns on the resource
|
||||
func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (response RuleResponse, patchedResource unstructured.Unstructured) {
|
||||
startTime := time.Now()
|
||||
|
@ -32,34 +27,39 @@ func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
glog.V(4).Infof("finished applying overlay rule %q (%v)", response.Name, response.RuleStats.ProcessingTime)
|
||||
}()
|
||||
|
||||
patches, err := processOverlayPatches(resource.UnstructuredContent(), rule.Mutation.Overlay)
|
||||
patches, overlayerr := processOverlayPatches(resource.UnstructuredContent(), rule.Mutation.Overlay)
|
||||
// resource does not satisfy the overlay pattern, we don't apply this rule
|
||||
if err != nil {
|
||||
if !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
switch overlayerr.statusCode {
|
||||
// condition key is not present in the resource, don't apply this rule
|
||||
// consider as success
|
||||
if strings.Contains(err.Error(), conditionalFieldEmpty) {
|
||||
case conditionNotPresent:
|
||||
glog.Infof("Resource %s/%s/%s: %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||
response.Success = true
|
||||
response.Message = fmt.Sprintf("Resource %s/%s/%s: %v.", resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
|
||||
response.Message = overlayerr.ErrorMsg()
|
||||
return response, resource
|
||||
}
|
||||
|
||||
// conditions are not met, don't apply this rule
|
||||
// consider as failure
|
||||
if strings.Contains(err.Error(), "Conditions are not met") {
|
||||
case conditionFailure:
|
||||
glog.Errorf("Resource %s/%s/%s does not meet the conditions in the rule %s with overlay pattern %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), rule.Name, rule.Mutation.Overlay)
|
||||
//TODO: send zero response and not consider this as applied?
|
||||
response.Success = false
|
||||
response.Message = fmt.Sprintf("Resource %s/%s/%s: %v.", resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
|
||||
response.Message = overlayerr.ErrorMsg()
|
||||
return response, resource
|
||||
// rule application failed
|
||||
case overlayFailure:
|
||||
glog.Errorf("Resource %s/%s/%s: failed to process overlay: %v in the rule %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg(), rule.Name)
|
||||
response.Success = false
|
||||
response.Message = fmt.Sprintf("failed to process overlay: %v", overlayerr.ErrorMsg())
|
||||
return response, resource
|
||||
default:
|
||||
glog.Errorf("Resource %s/%s/%s: Unknown type of error: %v", resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.Error())
|
||||
response.Success = false
|
||||
response.Message = fmt.Sprintf("Unknown type of error: %v", overlayerr.Error())
|
||||
return response, resource
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// rule application failed
|
||||
response.Success = false
|
||||
response.Message = fmt.Sprintf("failed to process overlay: %v", err)
|
||||
return response, resource
|
||||
}
|
||||
// convert to RAW
|
||||
resourceRaw, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
|
@ -93,20 +93,26 @@ func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
return response, patchedResource
|
||||
}
|
||||
|
||||
func processOverlayPatches(resource, overlay interface{}) ([][]byte, error) {
|
||||
if path, err := meetConditions(resource, overlay); err != nil {
|
||||
func processOverlayPatches(resource, overlay interface{}) ([][]byte, overlayError) {
|
||||
if path, overlayerr := meetConditions(resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
switch overlayerr.statusCode {
|
||||
// anchor key does not exist in the resource, skip applying policy
|
||||
if strings.Contains(err.Error(), conditionalFieldEmpty) {
|
||||
glog.V(4).Infof("Mutate rule: policy not applied: %v at %s", err, path)
|
||||
return nil, fmt.Errorf("policy not applied: %v at %s", err, path)
|
||||
}
|
||||
|
||||
case conditionNotPresent:
|
||||
glog.V(4).Infof("Mutate rule: policy not applied: %v at %s", overlayerr, path)
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("policy not applied: %v at %s", overlayerr.ErrorMsg(), path))
|
||||
// anchor key is not satisfied in the resource, skip applying policy
|
||||
glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, err)
|
||||
return nil, fmt.Errorf("Conditions are not met at %s, %v", path, err)
|
||||
case conditionFailure:
|
||||
glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, overlayerr)
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Conditions are not met at %s, %v", path, overlayerr))
|
||||
}
|
||||
}
|
||||
|
||||
return mutateResourceWithOverlay(resource, overlay)
|
||||
patchBytes, err := mutateResourceWithOverlay(resource, overlay)
|
||||
if err != nil {
|
||||
return patchBytes, newOverlayError(overlayFailure, err.Error())
|
||||
}
|
||||
|
||||
return patchBytes, overlayError{}
|
||||
}
|
||||
|
||||
// mutateResourceWithOverlay is a start of overlaying process
|
||||
|
|
|
@ -9,15 +9,15 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
)
|
||||
|
||||
func meetConditions(resource, overlay interface{}) (string, error) {
|
||||
func meetConditions(resource, overlay interface{}) (string, overlayError) {
|
||||
return checkConditions(resource, overlay, "/")
|
||||
}
|
||||
|
||||
// resource and overlay should be the same type
|
||||
func checkConditions(resource, overlay interface{}, path string) (string, error) {
|
||||
func checkConditions(resource, overlay interface{}, path string) (string, overlayError) {
|
||||
// overlay has no anchor, return true
|
||||
if !hasNestedAnchors(overlay) {
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
// resource item exists but has different type
|
||||
|
@ -26,10 +26,11 @@ func checkConditions(resource, overlay interface{}, path string) (string, error)
|
|||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||
if hasNestedAnchors(overlay) {
|
||||
glog.V(4).Infof("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)
|
||||
return path, fmt.Errorf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource)
|
||||
return path, newOverlayError(conditionFailure,
|
||||
fmt.Sprintf("Found anchor on different types of element at path %s: overlay %T %v, resource %T %v", path, overlay, overlay, resource, resource))
|
||||
|
||||
}
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
switch typedOverlay := overlay.(type) {
|
||||
|
@ -43,42 +44,43 @@ func checkConditions(resource, overlay interface{}, path string) (string, error)
|
|||
// anchor on non map/array is invalid:
|
||||
// - anchor defined on values
|
||||
glog.Warningln("Found invalid conditional anchor: anchor defined on values")
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
}
|
||||
|
||||
func checkConditionOnMap(resourceMap, overlayMap map[string]interface{}, path string) (string, error) {
|
||||
func checkConditionOnMap(resourceMap, overlayMap map[string]interface{}, path string) (string, overlayError) {
|
||||
anchors, overlayWithoutAnchor := getAnchorAndElementsFromMap(overlayMap)
|
||||
|
||||
// validate resource with conditions
|
||||
if newPath, err := validateConditionAnchorMap(resourceMap, anchors, path); err != nil {
|
||||
if newPath, err := validateConditionAnchorMap(resourceMap, anchors, path); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
|
||||
// traverse overlay pattern to further validate conditions
|
||||
if newPath, err := validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor, path); err != nil {
|
||||
if newPath, err := validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor, path); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
|
||||
// empty overlayMap
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, error) {
|
||||
func checkConditionOnArray(resource, overlay []interface{}, path string) (string, overlayError) {
|
||||
if 0 == len(overlay) {
|
||||
glog.Infof("Mutate overlay pattern is empty, path %s", path)
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) {
|
||||
glog.V(4).Infof("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])
|
||||
return path, fmt.Errorf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0])
|
||||
return path, newOverlayError(conditionFailure,
|
||||
fmt.Sprintf("Overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]))
|
||||
}
|
||||
|
||||
return checkConditionsOnArrayOfSameTypes(resource, overlay, path)
|
||||
}
|
||||
|
||||
func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, path string) (string, error) {
|
||||
func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, path string) (string, overlayError) {
|
||||
for key, overlayValue := range anchors {
|
||||
// skip if key does not have condition anchor
|
||||
if !anchor.IsConditionAnchor(key) {
|
||||
|
@ -91,25 +93,25 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
|
|||
if resourceValue, ok := resourceMap[noAnchorKey]; ok {
|
||||
// compare entire resourceValue block
|
||||
// return immediately on err since condition fails on this block
|
||||
if newPath, err := compareOverlay(resourceValue, overlayValue, curPath); err != nil {
|
||||
if newPath, err := compareOverlay(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
} else {
|
||||
// noAnchorKey doesn't exist in resource
|
||||
return curPath, fmt.Errorf("resource field is not present %s", noAnchorKey)
|
||||
return curPath, newOverlayError(conditionNotPresent, fmt.Sprintf("resource field is not present %s", noAnchorKey))
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
// compareOverlay compare values in anchormap and resourcemap
|
||||
// i.e. check if B1 == B2
|
||||
// overlay - (A): B1
|
||||
// resource - A: B2
|
||||
func compareOverlay(resource, overlay interface{}, path string) (string, error) {
|
||||
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
|
||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||
glog.Errorf("Found anchor on different types of element: overlay %T, resource %T\nSkip processing overlay.", overlay, resource)
|
||||
return path, fmt.Errorf("")
|
||||
glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T\nSkip processing overlay.", overlay, resource)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T\nSkip processing overlay.", overlay, resource))
|
||||
}
|
||||
|
||||
switch typedOverlay := overlay.(type) {
|
||||
|
@ -120,9 +122,9 @@ func compareOverlay(resource, overlay interface{}, path string) (string, error)
|
|||
curPath := path + noAnchorKey + "/"
|
||||
resourceVal, ok := typedResource[noAnchorKey]
|
||||
if !ok {
|
||||
return curPath, fmt.Errorf("Field %s is not present", noAnchorKey)
|
||||
return curPath, newOverlayError(conditionFailure, fmt.Sprintf("field %s is not present", noAnchorKey))
|
||||
}
|
||||
if newPath, err := compareOverlay(resourceVal, overlayVal, curPath); err != nil {
|
||||
if newPath, err := compareOverlay(resourceVal, overlayVal, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +132,7 @@ func compareOverlay(resource, overlay interface{}, path string) (string, error)
|
|||
typedResource := resource.([]interface{})
|
||||
for _, overlayElement := range typedOverlay {
|
||||
for _, resourceElement := range typedResource {
|
||||
if newPath, err := compareOverlay(resourceElement, overlayElement, path); err != nil {
|
||||
if newPath, err := compareOverlay(resourceElement, overlayElement, path); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
}
|
||||
|
@ -138,17 +140,17 @@ func compareOverlay(resource, overlay interface{}, path string) (string, error)
|
|||
case string, float64, int, int64, bool, nil:
|
||||
if !ValidateValueWithPattern(resource, overlay) {
|
||||
glog.V(4).Infof("Mutate rule: failed validating value %v with overlay %v", resource, overlay)
|
||||
return path, fmt.Errorf("failed validating value %v with overlay %v", resource, overlay)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("failed validating value %v with overlay %v", resource, overlay))
|
||||
}
|
||||
default:
|
||||
return path, fmt.Errorf("overlay has unknown type %T, value %v", overlay, overlay)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("overlay has unknown type %T, value %v", overlay, overlay))
|
||||
}
|
||||
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
// validateNonAnchorOverlayMap validate anchor condition in overlay block without anchor
|
||||
func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]interface{}, path string) (string, error) {
|
||||
func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]interface{}, path string) (string, overlayError) {
|
||||
// validate resource map (anchors could exist in resource)
|
||||
for key, overlayValue := range overlayWithoutAnchor {
|
||||
curPath := path + key + "/"
|
||||
|
@ -160,14 +162,14 @@ func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]in
|
|||
// the above case should be allowed
|
||||
continue
|
||||
}
|
||||
if newPath, err := checkConditions(resourceValue, overlayValue, curPath); err != nil {
|
||||
if newPath, err := checkConditions(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path string) (string, error) {
|
||||
func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path string) (string, overlayError) {
|
||||
switch overlay[0].(type) {
|
||||
case map[string]interface{}:
|
||||
return checkConditionsOnArrayOfMaps(resource, overlay, path)
|
||||
|
@ -175,17 +177,17 @@ func checkConditionsOnArrayOfSameTypes(resource, overlay []interface{}, path str
|
|||
for i, overlayElement := range overlay {
|
||||
curPath := path + strconv.Itoa(i) + "/"
|
||||
path, err := checkConditions(resource[i], overlayElement, curPath)
|
||||
if err != nil {
|
||||
if !reflect.DeepEqual(err, overlayError{}) {
|
||||
return path, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
return "", overlayError{}
|
||||
}
|
||||
|
||||
func checkConditionsOnArrayOfMaps(resource, overlay []interface{}, path string) (string, error) {
|
||||
func checkConditionsOnArrayOfMaps(resource, overlay []interface{}, path string) (string, overlayError) {
|
||||
var newPath string
|
||||
var err error
|
||||
var err overlayError
|
||||
|
||||
for i, overlayElement := range overlay {
|
||||
for _, resourceMap := range resource {
|
||||
|
@ -194,8 +196,8 @@ func checkConditionsOnArrayOfMaps(resource, overlay []interface{}, path string)
|
|||
// when resource has multiple same blocks of the overlay block
|
||||
// return true if there is one resource block meet the overlay pattern
|
||||
// reference: TestMeetConditions_AtleastOneExist
|
||||
if err == nil {
|
||||
return "", nil
|
||||
if reflect.DeepEqual(err, overlayError{}) {
|
||||
return "", overlayError{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package engine
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -28,7 +29,7 @@ func TestMeetConditions_NoAnchor(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(nil, overlay)
|
||||
assert.Assert(t, err == nil)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
||||
|
@ -81,7 +82,7 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, !reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`
|
||||
{
|
||||
|
@ -100,8 +101,8 @@ func TestMeetConditions_conditionalAnchorOnMap(t *testing.T) {
|
|||
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
_, overlayerr := meetConditions(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
}
|
||||
|
||||
func TestMeetConditions_DifferentTypes(t *testing.T) {
|
||||
|
@ -193,7 +194,7 @@ func TestMeetConditions_anchosInSameObject(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "failed validating value 443 with overlay 444")
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value 443 with overlay 444")
|
||||
}
|
||||
|
||||
func TestMeetConditions_anchorOnPeer(t *testing.T) {
|
||||
|
@ -251,7 +252,7 @@ func TestMeetConditions_anchorOnPeer(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
func TestMeetConditions_anchorsOnMetaAndSpec(t *testing.T) {
|
||||
|
@ -328,7 +329,7 @@ func TestMeetConditions_anchorsOnMetaAndSpec(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
var resourceRawAnchorOnPeers = []byte(`{
|
||||
|
@ -409,7 +410,7 @@ func TestMeetConditions_anchorsOnPeer_single(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
||||
|
@ -443,7 +444,7 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "failed validating value true with overlay false")
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value true with overlay false")
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
"spec": {
|
||||
|
@ -472,7 +473,7 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
"spec": {
|
||||
|
@ -501,7 +502,7 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
}
|
||||
|
||||
func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
||||
|
@ -535,7 +536,7 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
"spec": {
|
||||
|
@ -564,7 +565,7 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
"spec": {
|
||||
|
@ -593,7 +594,7 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||
}
|
||||
|
||||
func TestMeetConditions_AtleastOneExist(t *testing.T) {
|
||||
|
@ -652,6 +653,6 @@ func TestMeetConditions_AtleastOneExist(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
path, err := meetConditions(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
assert.Assert(t, len(path) == 0)
|
||||
}
|
||||
|
|
36
pkg/engine/overlayError.go
Normal file
36
pkg/engine/overlayError.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package engine
|
||||
|
||||
import "fmt"
|
||||
|
||||
type codeKey int
|
||||
|
||||
const (
|
||||
conditionFailure codeKey = iota
|
||||
conditionNotPresent
|
||||
overlayFailure
|
||||
)
|
||||
|
||||
type overlayError struct {
|
||||
statusCode codeKey
|
||||
errorMsg string
|
||||
}
|
||||
|
||||
// newOverlayError returns an overlay error using the statusCode and errorMsg
|
||||
func newOverlayError(code codeKey, msg string) overlayError {
|
||||
return overlayError{statusCode: code, errorMsg: msg}
|
||||
}
|
||||
|
||||
// StatusCode returns the codeKey wrapped with status code of the overlay error
|
||||
func (e overlayError) StatusCode() codeKey {
|
||||
return e.statusCode
|
||||
}
|
||||
|
||||
// ErrorMsg returns the string representation of the overlay error message
|
||||
func (e overlayError) ErrorMsg() string {
|
||||
return e.errorMsg
|
||||
}
|
||||
|
||||
// Error returns the string representation of the overlay error
|
||||
func (e overlayError) Error() string {
|
||||
return fmt.Sprintf("[overlayError:%v] %v", e.statusCode, e.errorMsg)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
)
|
||||
|
||||
func patchOverlay(rule kyverno.Rule, rawResource []byte) ([][]byte, error) {
|
||||
var resource interface{}
|
||||
if err := json.Unmarshal(rawResource, &resource); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//TODO: evaluate, Unmarshall called thrice
|
||||
resourceInfo := ParseResourceInfoFromObject(rawResource)
|
||||
patches, err := processOverlayPatches(resource, rule.Mutation.Overlay)
|
||||
if err != nil && strings.Contains(err.Error(), "Conditions are not met") {
|
||||
glog.Infof("Resource does not meet conditions in overlay pattern, resource=%s, rule=%s\n", resourceInfo, rule.Name)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return patches, err
|
||||
}
|
|
@ -65,8 +65,8 @@ func TestProcessOverlayPatches_NestedListWithAnchor(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
patch := JoinPatches(patches)
|
||||
|
@ -165,8 +165,8 @@ func TestProcessOverlayPatches_InsertIntoArray(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
patch := JoinPatches(patches)
|
||||
|
@ -286,8 +286,8 @@ func TestProcessOverlayPatches_TestInsertToArray(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, patches != nil)
|
||||
|
||||
patch := JoinPatches(patches)
|
||||
|
@ -369,8 +369,8 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
@ -458,7 +458,7 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err = ApplyPatches(resourceRaw, patches)
|
||||
|
@ -494,7 +494,7 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.Error(t, err, "Conditions are not met at /spec/template/metadata/labels/app/, failed validating value nginx with overlay nginx1")
|
||||
assert.Error(t, err, "[overlayError:0] Conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] failed validating value nginx with overlay nginx1")
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
||||
|
@ -522,8 +522,8 @@ func TestProcessOverlayPatches_AddingAnchor(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
@ -607,8 +607,8 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
@ -686,7 +686,7 @@ func TestProcessOverlayPatches_AddingAnchorInsideListElement(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, reflect.DeepEqual(err, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err = ApplyPatches(resourceRaw, patches)
|
||||
|
@ -749,8 +749,8 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
@ -807,7 +807,7 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.Error(t, err, "Conditions are not met at /subsets/0/ports/0/port/, failed validating value 443 with overlay 444")
|
||||
assert.Error(t, err, "[overlayError:0] Conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] failed validating value 443 with overlay 444")
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
||||
|
@ -888,8 +888,8 @@ func TestProcessOverlayPatches_insertWithCondition(t *testing.T) {
|
|||
json.Unmarshal(resourceRawAnchorOnPeers, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
@ -999,8 +999,8 @@ func TestProcessOverlayPatches_InsertIfNotPresentWithConditions(t *testing.T) {
|
|||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err := processOverlayPatches(resource, overlay)
|
||||
assert.NilError(t, err)
|
||||
patches, overlayerr := processOverlayPatches(resource, overlay)
|
||||
assert.Assert(t, reflect.DeepEqual(overlayerr, overlayError{}))
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
|
|
|
@ -3,10 +3,9 @@ package webhooks
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -33,8 +33,12 @@ func toBlockResource(engineReponses []engine.EngineResponse) bool {
|
|||
|
||||
func getErrorMsg(engineReponses []engine.EngineResponse) string {
|
||||
var str []string
|
||||
var resourceInfo string
|
||||
|
||||
for _, er := range engineReponses {
|
||||
if !er.IsSuccesful() {
|
||||
// resource in engineReponses is identical as this was called per admission request
|
||||
resourceInfo = fmt.Sprintf("%s/%s/%s", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||
str = append(str, fmt.Sprintf("failed policy %s", er.PolicyResponse.Policy))
|
||||
for _, rule := range er.PolicyResponse.Rules {
|
||||
if !rule.Success {
|
||||
|
@ -43,7 +47,7 @@ func getErrorMsg(engineReponses []engine.EngineResponse) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(str, "\n")
|
||||
return fmt.Sprintf("Resource %s: %s", resourceInfo, strings.Join(str, "\n"))
|
||||
}
|
||||
|
||||
//ArrayFlags to store filterkinds
|
||||
|
|
|
@ -33,10 +33,6 @@ if [ -z "${namespace}" ]; then # controller should be launched locally
|
|||
|
||||
${certsGenerator} "--service=${service_name}" "--serverIp=${serverIp}" || exit 2
|
||||
|
||||
echo "Applying webhook..."
|
||||
kubectl delete -f definitions/MutatingWebhookConfiguration_debug.yaml
|
||||
kubectl create -f definitions/MutatingWebhookConfiguration_debug.yaml || exit 3
|
||||
|
||||
kubectl delete -f definitions/install.yaml
|
||||
kubectl create -f definitions/install.yaml || exit 3
|
||||
|
||||
|
@ -59,10 +55,6 @@ else # controller should be launched within a cluster
|
|||
kubectl delete -f crd/deployment.yaml
|
||||
kubectl create -f crd/deployment.yaml || exit 5
|
||||
|
||||
echo "Applying webhook..."
|
||||
kubectl delete -f crd/MutatingWebhookConfiguration.yaml
|
||||
kubectl create -f crd/MutatingWebhookConfiguration.yaml || exit 3
|
||||
|
||||
kubectl delete -f crd/crd.yaml
|
||||
kubectl create -f crd/crd.yaml || exit 3
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue