1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 07:57:07 +00:00
kyverno/pkg/engine/patches.go

139 lines
3.8 KiB
Go
Raw Normal View History

2019-05-21 18:27:56 +03:00
package engine
2019-03-15 17:58:16 +02:00
import (
"encoding/json"
2019-08-23 18:34:23 -07:00
"fmt"
"strings"
"time"
2019-03-15 17:58:16 +02:00
2019-06-28 17:11:19 -07:00
"github.com/golang/glog"
2019-08-23 18:34:23 -07:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2019-06-28 17:11:19 -07:00
2019-03-15 17:58:16 +02:00
jsonpatch "github.com/evanphx/json-patch"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
2019-03-15 17:58:16 +02:00
)
// JoinPatches joins array of serialized JSON patches to the single JSONPatch array
func JoinPatches(patches [][]byte) []byte {
var result []byte
2019-03-15 17:58:16 +02:00
if len(patches) == 0 {
return result
}
result = append(result, []byte("[\n")...)
for index, patch := range patches {
result = append(result, patch...)
if index != len(patches)-1 {
2019-03-15 17:58:16 +02:00
result = append(result, []byte(",\n")...)
}
}
result = append(result, []byte("\n]")...)
return result
}
// applyPatch applies patch for resource, returns patched resource.
func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
patchesList := [][]byte{patchRaw}
return ApplyPatches(resource, patchesList)
}
// ApplyPatches patches given resource with given patches and returns patched document
func ApplyPatches(resource []byte, patches [][]byte) ([]byte, error) {
joinedPatches := JoinPatches(patches)
patch, err := jsonpatch.DecodePatch(joinedPatches)
2019-03-15 17:58:16 +02:00
if err != nil {
return nil, err
2019-03-15 17:58:16 +02:00
}
patchedDocument, err := patch.Apply(resource)
if err != nil {
return resource, err
}
return patchedDocument, err
2019-03-15 17:58:16 +02:00
}
2019-08-23 18:34:23 -07:00
//ApplyPatchNew patches given resource with given joined patches
2019-08-23 18:34:23 -07:00
func ApplyPatchNew(resource, patch []byte) ([]byte, error) {
jsonpatch, err := jsonpatch.DecodePatch(patch)
2019-08-23 18:34:23 -07:00
if err != nil {
return nil, err
}
patchedResource, err := jsonpatch.Apply(resource)
if err != nil {
return nil, err
}
return patchedResource, err
}
func processPatches(rule kyverno.Rule, resource unstructured.Unstructured) (response RuleResponse, patchedResource unstructured.Unstructured) {
2019-08-23 18:34:23 -07:00
startTime := time.Now()
glog.V(4).Infof("started JSON patch rule %q (%v)", rule.Name, startTime)
response.Name = rule.Name
response.Type = Mutation.String()
defer func() {
response.RuleStats.ProcessingTime = time.Since(startTime)
glog.V(4).Infof("finished JSON patch rule %q (%v)", response.Name, response.RuleStats.ProcessingTime)
}()
// convert to RAW
resourceRaw, err := resource.MarshalJSON()
if err != nil {
response.Success = false
glog.Infof("unable to marshall resource: %v", err)
response.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return response, resource
}
var errs []error
var patches [][]byte
for _, patch := range rule.Mutation.Patches {
// JSON patch
patchRaw, err := json.Marshal(patch)
if err != nil {
glog.V(4).Infof("failed to marshall JSON patch %v: %v", patch, err)
errs = append(errs, err)
continue
}
2019-08-26 16:10:19 -07:00
patchResource, err := applyPatch(resourceRaw, patchRaw)
2019-08-23 18:34:23 -07:00
// TODO: continue on error if one of the patches fails, will add the failure event in such case
if err != nil && patch.Operation == "remove" {
glog.Info(err)
continue
}
if err != nil {
errs = append(errs, err)
continue
}
resourceRaw = patchResource
patches = append(patches, patchRaw)
}
// error while processing JSON patches
if len(errs) > 0 {
response.Success = false
2019-08-30 01:08:54 -07:00
response.Message = fmt.Sprintf("failed to process JSON patches: %v", func() string {
2019-08-23 18:34:23 -07:00
var str []string
for _, err := range errs {
str = append(str, err.Error())
}
return strings.Join(str, ";")
}())
return response, resource
}
err = patchedResource.UnmarshalJSON(resourceRaw)
if err != nil {
2019-08-30 01:08:54 -07:00
glog.Infof("failed to unmarshall resource to undstructured: %v", err)
2019-08-23 18:34:23 -07:00
response.Success = false
response.Message = fmt.Sprintf("failed to process JSON patches: %v", err)
return response, resource
}
// JSON patches processed succesfully
response.Success = true
response.Message = fmt.Sprintf("succesfully process JSON patches")
response.Patches = patches
return response, patchedResource
}