/
mutation.go
130 lines (106 loc) · 4.57 KB
/
mutation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package engine
import (
"time"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine/mutate"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/variables"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
const (
// PodControllerCronJob represent CronJob string
PodControllerCronJob = "CronJob"
//PodControllers stores the list of Pod-controllers in csv string
PodControllers = "DaemonSet,Deployment,Job,StatefulSet,CronJob"
//PodControllersAnnotation defines the annotation key for Pod-Controllers
PodControllersAnnotation = "pod-policies.kyverno.io/autogen-controllers"
)
// Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now()
policy := policyContext.Policy
patchedResource := policyContext.NewResource
ctx := policyContext.JSONContext
resCache := policyContext.ResourceCache
logger := log.Log.WithName("EngineMutate").WithValues("policy", policy.Name, "kind", patchedResource.GetKind(),
"namespace", patchedResource.GetNamespace(), "name", patchedResource.GetName())
logger.V(4).Info("start policy processing", "startTime", startTime)
startMutateResultResponse(resp, policy, patchedResource)
defer endMutateResultResponse(logger, resp, startTime)
if ManagedPodResource(policy, patchedResource) {
logger.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
resp.PatchedResource = patchedResource
return
}
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
for _, rule := range policy.Spec.Rules {
var ruleResponse response.RuleResponse
logger := logger.WithValues("rule", rule.Name)
if !rule.HasMutate() {
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 satisfy a policy rule resource description
excludeResource := []string{}
if len(policyContext.ExcludeGroupRole) > 0 {
excludeResource = policyContext.ExcludeGroupRole
}
if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource); err != nil {
logger.V(4).Info("rule not matched", "reason", err.Error())
continue
}
logger.V(3).Info("matched mutate rule")
policyContext.JSONContext.Restore()
if err := LoadContext(logger, rule.Context, resCache, policyContext); err != nil {
logger.V(2).Info("failed to load context", "reason", err.Error())
continue
}
// operate on the copy of the conditions, as we perform variable substitution
copyConditions := copyConditions(rule.Conditions)
// evaluate pre-conditions
// - handle variable substitutions
if !variables.EvaluateConditions(logger, ctx, copyConditions) {
logger.V(3).Info("resource fails the preconditions")
continue
}
mutation := rule.Mutation.DeepCopy()
mutateHandler := mutate.CreateMutateHandler(rule.Name, mutation, patchedResource, ctx, logger)
ruleResponse, patchedResource = mutateHandler.Handle()
if ruleResponse.Success {
// - overlay pattern does not match the resource conditions
if ruleResponse.Patches == nil {
continue
}
logger.V(4).Info("mutate rule applied successfully", "ruleName", rule.Name)
}
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount(resp)
}
resp.PatchedResource = patchedResource
return resp
}
func incrementAppliedRuleCount(resp *response.EngineResponse) {
resp.PolicyResponse.RulesAppliedCount++
}
func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) {
if resp == nil {
return
}
resp.PolicyResponse.Policy = policy.Name
resp.PolicyResponse.Resource.Name = resource.GetName()
resp.PolicyResponse.Resource.Namespace = resource.GetNamespace()
resp.PolicyResponse.Resource.Kind = resource.GetKind()
resp.PolicyResponse.Resource.APIVersion = resource.GetAPIVersion()
}
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) {
if resp == nil {
return
}
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
logger.V(5).Info("finished processing policy", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}