1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/engine/mutation.go

191 lines
6.5 KiB
Go
Raw Normal View History

2019-05-13 18:17:28 -07:00
package engine
2019-05-09 22:26:22 -07:00
import (
"reflect"
2019-08-19 16:40:10 -07:00
"time"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"github.com/nirmata/kyverno/pkg/info"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2019-05-09 22:26:22 -07:00
)
// Mutate performs mutation. Overlay first and then mutation patches
2019-08-19 17:26:52 -07:00
func Mutate(policy kyverno.Policy, resource unstructured.Unstructured) (response EngineResponse) {
// var response EngineResponse
var allPatches, rulePatches [][]byte
var err error
var errs []error
ris := []info.RuleInfo{}
2019-08-19 16:40:10 -07:00
startTime := time.Now()
glog.V(4).Infof("started applying mutation rules of policy %q (%v)", policy.Name, startTime)
defer func() {
2019-08-19 18:57:19 -07:00
response.ExecutionTime = time.Since(startTime)
glog.V(4).Infof("finished applying mutation rules policy %v (%v)", policy.Name, response.ExecutionTime)
glog.V(4).Infof("Mutation Rules appplied succesfully count %v for policy %q", response.RulesAppliedCount, policy.Name)
2019-08-19 16:40:10 -07:00
}()
incrementAppliedRuleCount := func() {
2019-08-19 16:40:10 -07:00
// rules applied succesfully count
2019-08-19 18:57:19 -07:00
response.RulesAppliedCount++
2019-08-19 16:40:10 -07:00
}
patchedDocument, err := resource.MarshalJSON()
if err != nil {
glog.Errorf("unable to marshal resource : %v\n", err)
}
if err != nil {
glog.V(4).Infof("unable to marshal resource : %v", err)
2019-08-19 18:57:19 -07:00
response.PatchedResource = resource
return response
}
2019-05-09 22:26:22 -07:00
for _, rule := range policy.Spec.Rules {
if reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) {
continue
2019-05-09 22:26:22 -07:00
}
2019-08-09 11:08:02 -07:00
// check if the resource satisfies the filter conditions defined in the rule
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description
ok := MatchesResourceDescription(resource, rule)
if !ok {
2019-08-09 12:59:37 -07:00
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule ", resource.GetNamespace(), resource.GetName())
continue
}
2019-08-09 12:59:37 -07:00
ruleInfo := info.NewRuleInfo(rule.Name, info.Mutation)
2019-08-09 11:08:02 -07:00
// Process Overlay
if rule.Mutation.Overlay != nil {
2019-08-23 18:34:23 -07:00
// ruleRespone := processOverlay(rule, res)
rulePatches, err = processOverlay(rule, patchedDocument)
2019-07-25 16:20:22 -04:00
if err == nil {
if len(rulePatches) == 0 {
2019-07-24 14:25:51 -04:00
// if array elements dont match then we skip(nil patch, no error)
// or if acnohor is defined and doenst match
// policy is not applicable
2019-08-09 12:59:37 -07:00
glog.V(4).Info("overlay does not match, so skipping applying rule")
2019-07-24 14:25:51 -04:00
continue
}
2019-08-09 12:59:37 -07:00
ruleInfo.Addf("Rule %s: Overlay succesfully applied.", rule.Name)
2019-07-25 16:20:22 -04:00
// strip slashes from string
2019-08-19 16:10:10 -07:00
ruleInfo.Patches = rulePatches
allPatches = append(allPatches, rulePatches...)
glog.V(4).Infof("overlay applied succesfully on resource %s/%s", resource.GetNamespace(), resource.GetName())
2019-07-24 06:33:51 -04:00
} else {
2019-08-09 11:08:02 -07:00
glog.V(4).Infof("failed to apply overlay: %v", err)
2019-08-09 12:59:37 -07:00
ruleInfo.Fail()
ruleInfo.Addf("failed to apply overlay: %v", err)
}
incrementAppliedRuleCount()
}
// Process Patches
if len(rule.Mutation.Patches) != 0 {
rulePatches, errs = processPatches(rule, patchedDocument)
if len(errs) > 0 {
2019-08-09 12:59:37 -07:00
ruleInfo.Fail()
for _, err := range errs {
2019-08-09 11:08:02 -07:00
glog.V(4).Infof("failed to apply patches: %v", err)
2019-08-09 12:59:37 -07:00
ruleInfo.Addf("patches application has failed, err %v.", err)
}
2019-06-05 16:44:53 +03:00
} else {
2019-08-09 12:59:37 -07:00
glog.V(4).Infof("patches applied succesfully on resource %s/%s", resource.GetNamespace(), resource.GetName())
ruleInfo.Addf("Patches succesfully applied.")
2019-08-19 16:10:10 -07:00
ruleInfo.Patches = rulePatches
2019-07-19 20:30:55 -07:00
allPatches = append(allPatches, rulePatches...)
}
incrementAppliedRuleCount()
}
patchedDocument, err = ApplyPatches(patchedDocument, rulePatches)
if err != nil {
glog.Errorf("Failed to apply patches on ruleName=%s, err%v\n:", rule.Name, err)
}
ris = append(ris, ruleInfo)
2019-05-09 22:26:22 -07:00
}
patchedResource, err := ConvertToUnstructured(patchedDocument)
2019-08-19 16:10:10 -07:00
if err != nil {
glog.Errorf("Failed to convert patched resource to unstructuredtype, err%v\n:", err)
2019-08-19 18:57:19 -07:00
response.PatchedResource = resource
return response
2019-08-19 16:10:10 -07:00
}
2019-08-19 18:57:19 -07:00
response.Patches = allPatches
response.PatchedResource = *patchedResource
response.RuleInfos = ris
return response
2019-05-09 22:26:22 -07:00
}
2019-08-23 18:34:23 -07:00
//MutateNew ...
func MutateNew(policy kyverno.Policy, resource unstructured.Unstructured) (response EngineResponseNew) {
startTime := time.Now()
// policy information
func() {
// set policy information
response.PolicyResponse.Policy = policy.Name
// resource details
response.PolicyResponse.Resource.Name = resource.GetName()
response.PolicyResponse.Resource.Namespace = resource.GetNamespace()
response.PolicyResponse.Resource.Kind = resource.GetKind()
response.PolicyResponse.Resource.APIVersion = resource.GetAPIVersion()
}()
glog.V(4).Infof("started applying mutation rules of policy %q (%v)", policy.Name, startTime)
defer func() {
response.PolicyResponse.ProcessingTime = time.Since(startTime)
glog.V(4).Infof("finished applying mutation rules policy %v (%v)", policy.Name, response.PolicyResponse.ProcessingTime)
glog.V(4).Infof("Mutation Rules appplied succesfully count %v for policy %q", response.PolicyResponse.RulesAppliedCount, policy.Name)
}()
incrementAppliedRuleCount := func() {
// rules applied succesfully count
response.PolicyResponse.RulesAppliedCount++
}
var patchedResource unstructured.Unstructured
for _, rule := range policy.Spec.Rules {
//TODO: to be checked before calling the resources as well
if reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) {
continue
}
// check if the resource satisfies the filter conditions defined in the rule
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description
ok := MatchesResourceDescription(resource, rule)
if !ok {
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule ", resource.GetNamespace(), resource.GetName())
continue
}
// Process Overlay
if rule.Mutation.Overlay != nil {
var ruleResponse RuleResponse
ruleResponse, patchedResource = processOverlayNew(rule, resource)
if reflect.DeepEqual(ruleResponse, (RuleResponse{})) {
// overlay pattern does not match the resource conditions
continue
}
response.PolicyResponse.Rules = append(response.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount()
}
// Process Patches
if rule.Mutation.Patches != nil {
var ruleResponse RuleResponse
ruleResponse, patchedResource = processPatchesNew(rule, resource)
response.PolicyResponse.Rules = append(response.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount()
}
}
// send the patched resource
response.PatchedResource = patchedResource
return response
}