mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
package webhooks
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/nirmata/kyverno/pkg/engine"
|
|
|
|
jsonpatch "github.com/evanphx/json-patch"
|
|
"github.com/golang/glog"
|
|
)
|
|
|
|
const (
|
|
policyAnnotation = "policies.kyverno.io"
|
|
// lastAppliedPatches = policyAnnotation + "last-applied-patches"
|
|
)
|
|
|
|
type policyPatch struct {
|
|
PolicyName string `json:"policyname"`
|
|
// RulePatches []string `json:"patches"`
|
|
RulePatches interface{} `json:"patches"`
|
|
}
|
|
|
|
type rulePatch struct {
|
|
RuleName string `json:"rulename"`
|
|
Op string `json:"op"`
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
type response struct {
|
|
Op string `json:"op"`
|
|
Path string `json:"path"`
|
|
Value interface{} `json:"value"`
|
|
}
|
|
|
|
func generateAnnotationPatches(annotations map[string]string, policyResponse engine.PolicyResponse) []byte {
|
|
if annotations == nil {
|
|
annotations = map[string]string{}
|
|
}
|
|
var patchResponse response
|
|
value := generateAnnotationsFromPolicyResponse(policyResponse)
|
|
if value == nil {
|
|
// no patches or error while processing patches
|
|
return nil
|
|
}
|
|
if _, ok := annotations[policyAnnotation]; ok {
|
|
// create update patch string
|
|
patchResponse = response{
|
|
Op: "replace",
|
|
Path: "/metadata/annotations/" + policyAnnotation,
|
|
Value: string(value),
|
|
}
|
|
} else {
|
|
patchResponse = response{
|
|
Op: "add",
|
|
Path: "/metadata/annotations",
|
|
Value: map[string]string{policyAnnotation: string(value)},
|
|
}
|
|
}
|
|
|
|
patchByte, _ := json.Marshal(patchResponse)
|
|
|
|
// check the patch
|
|
_, err := jsonpatch.DecodePatch([]byte("[" + string(patchByte) + "]"))
|
|
if err != nil {
|
|
glog.Errorf("Failed to make patch from annotation'%s', err: %v\n ", string(patchByte), err)
|
|
}
|
|
|
|
return patchByte
|
|
}
|
|
|
|
// func prepareAnnotationPatches(resource *unstructured.Unstructured, policyInfos []info.PolicyInfo) []byte {
|
|
// annots := resource.GetAnnotations()
|
|
// if annots == nil {
|
|
// annots = map[string]string{}
|
|
// }
|
|
|
|
// var patchResponse response
|
|
// value := annotationFromPolicies(policyInfos)
|
|
// if _, ok := annots[policyAnnotation]; ok {
|
|
// // create update patch string
|
|
// patchResponse = response{
|
|
// Op: "replace",
|
|
// Path: "/metadata/annotations/" + policyAnnotation,
|
|
// Value: string(value),
|
|
// }
|
|
// } else {
|
|
// patchResponse = response{
|
|
// Op: "add",
|
|
// Path: "/metadata/annotations",
|
|
// Value: map[string]string{policyAnnotation: string(value)},
|
|
// }
|
|
// }
|
|
|
|
// patchByte, _ := json.Marshal(patchResponse)
|
|
|
|
// // check the patch
|
|
// _, err := jsonpatch.DecodePatch([]byte("[" + string(patchByte) + "]"))
|
|
// if err != nil {
|
|
// glog.Errorf("Failed to make patch from annotation'%s', err: %v\n ", string(patchByte), err)
|
|
// }
|
|
|
|
// return patchByte
|
|
// }
|
|
|
|
// func annotationFromPolicies(policyInfos []info.PolicyInfo) []byte {
|
|
// var policyPatches []policyPatch
|
|
// for _, policyInfo := range policyInfos {
|
|
// var pp policyPatch
|
|
|
|
// pp.PolicyName = policyInfo.Name
|
|
// pp.RulePatches = annotationFromPolicy(policyInfo)
|
|
// policyPatches = append(policyPatches, pp)
|
|
// }
|
|
|
|
// result, _ := json.Marshal(policyPatches)
|
|
|
|
// return result
|
|
// }
|
|
|
|
func generateAnnotationsFromPolicyResponse(policyResponse engine.PolicyResponse) []byte {
|
|
var rulePatches []rulePatch
|
|
// generate annotation for each mutation JSON patch to be applied on the resource
|
|
for _, rule := range policyResponse.Rules {
|
|
var patchmap map[string]string
|
|
patch := engine.JoinPatches(rule.Patches)
|
|
if err := json.Unmarshal(patch, &patchmap); err != nil {
|
|
glog.Errorf("Failed to parse patch bytes, err: %v\n", err)
|
|
continue
|
|
}
|
|
|
|
rp := rulePatch{
|
|
RuleName: rule.Name,
|
|
Op: patchmap["op"],
|
|
Path: patchmap["path"]}
|
|
|
|
rulePatches = append(rulePatches, rp)
|
|
glog.V(4).Infof("Annotation value prepared: %v\n", rulePatches)
|
|
|
|
}
|
|
patch, err := json.Marshal(rulePatches)
|
|
if err != nil {
|
|
glog.Info("failed to marshall: %v", err)
|
|
return nil
|
|
}
|
|
return patch
|
|
}
|
|
|
|
// func annotationFromPolicy(policyInfo info.PolicyInfo) []rulePatch {
|
|
// if !policyInfo.IsSuccessful() {
|
|
// glog.V(2).Infof("Policy %s failed, skip preparing annotation\n", policyInfo.Name)
|
|
// return nil
|
|
// }
|
|
|
|
// var rulePatches []rulePatch
|
|
// for _, ruleInfo := range policyInfo.Rules {
|
|
|
|
// for _, patch := range ruleInfo.Patches {
|
|
// var patchmap map[string]string
|
|
|
|
// if err := json.Unmarshal(patch, &patchmap); err != nil {
|
|
// glog.Errorf("Failed to parse patch bytes, err: %v\n", err)
|
|
// continue
|
|
// }
|
|
|
|
// rp := rulePatch{
|
|
// RuleName: ruleInfo.Name,
|
|
// Op: patchmap["op"],
|
|
// Path: patchmap["path"]}
|
|
|
|
// rulePatches = append(rulePatches, rp)
|
|
// glog.V(4).Infof("Annotation value prepared: %v\n", rulePatches)
|
|
// }
|
|
// }
|
|
|
|
// return rulePatches
|
|
// }
|