1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Merge pull request #210 from nirmata/157_bug

resource patched after every rule + rm PatchBytes
This commit is contained in:
shuting 2019-07-08 10:47:55 -07:00 committed by GitHub
commit db28e0fb63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 44 deletions

View file

@ -8,9 +8,9 @@ import (
)
// Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, []*info.RuleInfo) {
var allPatches []PatchBytes
patchedDocument := rawResource
func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, []*info.RuleInfo) {
var allPatches [][]byte
var err error
ris := []*info.RuleInfo{}
for _, rule := range policy.Spec.Rules {
@ -31,26 +31,36 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
ri.Fail()
ri.Addf("Rule %s: Overlay application has failed, err %s.", rule.Name, err)
} else {
ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name)
//TODO: patchbytes -> string
//glog.V(3).Info(" Overlay succesfully applied. Patch %s", string(overlayPatches))
allPatches = append(allPatches, overlayPatches...)
// Apply the JSON patches from the rule to the resource
rawResource, err = ApplyPatches(rawResource, overlayPatches)
if err != nil {
ri.Fail()
ri.Addf("Unable to apply JSON patch to resource, err %s.", err)
} else {
ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name)
allPatches = append(allPatches, overlayPatches...)
}
}
}
// Process Patches
if len(rule.Mutation.Patches) != 0 {
rulePatches, errs := ProcessPatches(rule, patchedDocument)
rulePatches, errs := ProcessPatches(rule, rawResource)
if len(errs) > 0 {
ri.Fail()
for _, err := range errs {
ri.Addf("Rule %s: Patches application has failed, err %s.", rule.Name, err)
}
} else {
ri.Addf("Rule %s: Patches succesfully applied.", rule.Name)
//TODO: patchbytes -> string
//glog.V(3).Info("Patches succesfully applied. Patch %s", string(overlayPatches))
allPatches = append(allPatches, rulePatches...)
// Apply the JSON patches from the rule to the resource
rawResource, err = ApplyPatches(rawResource, rulePatches)
if err != nil {
ri.Fail()
ri.Addf("Unable to apply JSON patch to resource, err %s.", err)
} else {
ri.Addf("Rule %s: Patches succesfully applied.", rule.Name)
allPatches = append(allPatches, rulePatches...)
}
}
}
ris = append(ris, ri)

View file

@ -16,10 +16,10 @@ import (
// ProcessOverlay handles validating admission request
// Checks the target resources for rules defined in the policy
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, error) {
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, error) {
var resource interface{}
var appliedPatches []PatchBytes
var appliedPatches [][]byte
err := json.Unmarshal(rawResource, &resource)
if err != nil {
return nil, err
@ -35,14 +35,14 @@ func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVe
}
// mutateResourceWithOverlay is a start of overlaying process
func mutateResourceWithOverlay(resource, pattern interface{}) ([]PatchBytes, error) {
func mutateResourceWithOverlay(resource, pattern interface{}) ([][]byte, error) {
// It assumes that mutation is started from root, so "/" is passed
return applyOverlay(resource, pattern, "/")
}
// applyOverlay detects type of current item and goes down through overlay and resource trees applying overlay
func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlay(resource, overlay interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
// resource item exists but has different type - replace
// all subtree within this path by overlay
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
@ -57,8 +57,8 @@ func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, err
}
// applyOverlayForSameTypes is applyOverlay for cases when TypeOf(resource) == TypeOf(overlay)
func applyOverlayForSameTypes(resource, overlay interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayForSameTypes(resource, overlay interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
// detect the type of resource and overlay and select corresponding handler
switch typedOverlay := overlay.(type) {
@ -93,8 +93,8 @@ func applyOverlayForSameTypes(resource, overlay interface{}, path string) ([]Pat
}
// for each overlay and resource map elements applies overlay
func applyOverlayToMap(resourceMap, overlayMap map[string]interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayToMap(resourceMap, overlayMap map[string]interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
for key, value := range overlayMap {
// skip anchor element because it has condition, not
@ -130,8 +130,8 @@ func applyOverlayToMap(resourceMap, overlayMap map[string]interface{}, path stri
}
// for each overlay and resource array elements applies overlay
func applyOverlayToArray(resource, overlay []interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayToArray(resource, overlay []interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
if 0 == len(overlay) {
return nil, errors.New("Empty array detected in the overlay")
@ -156,8 +156,8 @@ func applyOverlayToArray(resource, overlay []interface{}, path string) ([]PatchB
}
// applyOverlayToArrayOfSameTypes applies overlay to array elements if they (resource and overlay elements) have same type
func applyOverlayToArrayOfSameTypes(resource, overlay []interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayToArrayOfSameTypes(resource, overlay []interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
switch overlay[0].(type) {
case map[string]interface{}:
@ -181,8 +181,8 @@ func applyOverlayToArrayOfSameTypes(resource, overlay []interface{}, path string
}
// Array of maps needs special handling as far as it can have anchors.
func applyOverlayToArrayOfMaps(resource, overlay []interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayToArrayOfMaps(resource, overlay []interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
lastElementIdx := len(resource)
for i, overlayElement := range overlay {
@ -222,8 +222,8 @@ func applyOverlayToArrayOfMaps(resource, overlay []interface{}, path string) ([]
return appliedPatches, nil
}
func applyOverlayWithAnchors(resource []interface{}, overlay interface{}, anchors map[string]interface{}, path string) ([]PatchBytes, error) {
var appliedPatches []PatchBytes
func applyOverlayWithAnchors(resource []interface{}, overlay interface{}, anchors map[string]interface{}, path string) ([][]byte, error) {
var appliedPatches [][]byte
for i, resourceElement := range resource {
typedResource := resourceElement.(map[string]interface{})
@ -242,15 +242,15 @@ func applyOverlayWithAnchors(resource []interface{}, overlay interface{}, anchor
return appliedPatches, nil
}
func insertSubtree(overlay interface{}, path string) (PatchBytes, error) {
func insertSubtree(overlay interface{}, path string) ([]byte, error) {
return processSubtree(overlay, path, "add")
}
func replaceSubtree(overlay interface{}, path string) (PatchBytes, error) {
func replaceSubtree(overlay interface{}, path string) ([]byte, error) {
return processSubtree(overlay, path, "replace")
}
func processSubtree(overlay interface{}, path string, op string) (PatchBytes, error) {
func processSubtree(overlay interface{}, path string, op string) ([]byte, error) {
if len(path) > 1 && path[len(path)-1] == '/' {
path = path[:len(path)-1]
@ -270,7 +270,7 @@ func processSubtree(overlay interface{}, path string, op string) (PatchBytes, er
return nil, fmt.Errorf("Failed to make '%s' patch from an overlay '%s' for path %s", op, value, path)
}
return PatchBytes(patchStr), nil
return []byte(patchStr), nil
}
// converts overlay to JSON string to be inserted into the JSON Patch

View file

@ -10,12 +10,9 @@ import (
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
)
// PatchBytes stands for []byte
type PatchBytes []byte
// ProcessPatches Returns array from separate patches that can be applied to the document
// Returns error ONLY in case when creation of resource should be denied.
func ProcessPatches(rule kubepolicy.Rule, resource []byte) (allPatches []PatchBytes, errs []error) {
func ProcessPatches(rule kubepolicy.Rule, resource []byte) (allPatches [][]byte, errs []error) {
if len(resource) == 0 {
errs = append(errs, errors.New("Source document for patching is empty"))
return nil, errs
@ -48,8 +45,8 @@ func ProcessPatches(rule kubepolicy.Rule, resource []byte) (allPatches []PatchBy
}
// JoinPatches joins array of serialized JSON patches to the single JSONPatch array
func JoinPatches(patches []PatchBytes) PatchBytes {
var result PatchBytes
func JoinPatches(patches [][]byte) []byte {
var result []byte
if len(patches) == 0 {
return result
}
@ -67,12 +64,12 @@ func JoinPatches(patches []PatchBytes) PatchBytes {
// applyPatch applies patch for resource, returns patched resource.
func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
patchesList := []PatchBytes{patchRaw}
patchesList := [][]byte{patchRaw}
return ApplyPatches(resource, patchesList)
}
// ApplyPatches patches given resource with given patches and returns patched document
func ApplyPatches(resource []byte, patches []PatchBytes) ([]byte, error) {
func ApplyPatches(resource []byte, patches [][]byte) ([]byte, error) {
joinedPatches := JoinPatches(patches)
patch, err := jsonpatch.DecodePatch(joinedPatches)
if err != nil {

View file

@ -153,7 +153,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
}
}
var allPatches []engine.PatchBytes
var allPatches [][]byte
policyInfos := []*info.PolicyInfo{}
for _, policy := range policies {
// check if policy has a rule for the admission request kind
@ -330,6 +330,7 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
return admissionReview
}
//HandlePolicyValidation performs the validation check on policy resource
func (ws *WebhookServer) HandlePolicyValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
return ws.validateUniqueRuleName(request.Object.Raw)
}
@ -351,9 +352,8 @@ func (ws *WebhookServer) validateUniqueRuleName(rawPolicy []byte) *v1beta1.Admis
Message: msg,
},
}
} else {
ruleNames = append(ruleNames, rule.Name)
}
ruleNames = append(ruleNames, rule.Name)
}
glog.V(3).Infof("Policy validation passed.")