mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 10:28:36 +00:00
add process existing for mutation & validation + come cleanup
This commit is contained in:
parent
4bf3043a18
commit
e7b538be79
16 changed files with 279 additions and 131 deletions
|
@ -48,7 +48,7 @@ func (p *Policy) getOverAllStatus() string {
|
|||
return "Success"
|
||||
}
|
||||
|
||||
func getRules(rules []*pinfo.RuleInfo, ruleType pinfo.RuleType) map[string]Rule {
|
||||
func getRules(rules []pinfo.RuleInfo, ruleType pinfo.RuleType) map[string]Rule {
|
||||
if len(rules) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,107 +1,105 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ProcessExisting checks for mutation and validation violations of existing resources
|
||||
func ProcessExisting(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) []info.PolicyInfo {
|
||||
glog.Infof("Applying policy %s on existing resources", policy.Name)
|
||||
// key uid
|
||||
resourceMap := ListResourcesThatApplyToPolicy(client, policy, filterK8Resources)
|
||||
policyInfos := []info.PolicyInfo{}
|
||||
// for the filtered resource apply policy
|
||||
for _, v := range resourceMap {
|
||||
return nil
|
||||
// glog.Infof("Applying policy %s on existing resources", policy.Name)
|
||||
// // key uid
|
||||
// resourceMap := ListResourcesThatApplyToPolicy(client, policy, filterK8Resources)
|
||||
// policyInfos := []info.PolicyInfo{}
|
||||
// // for the filtered resource apply policy
|
||||
// for _, v := range resourceMap {
|
||||
|
||||
policyInfo, err := applyPolicy(client, policy, v)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, v.Resource.GetName(), v.Resource.GetNamespace())
|
||||
glog.Error(err)
|
||||
continue
|
||||
}
|
||||
policyInfos = append(policyInfos, policyInfo)
|
||||
}
|
||||
// policyInfo, err := applyPolicy(client, policy, v)
|
||||
// if err != nil {
|
||||
// glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, v.Resource.GetName(), v.Resource.GetNamespace())
|
||||
// glog.Error(err)
|
||||
// continue
|
||||
// }
|
||||
// policyInfos = append(policyInfos, policyInfo)
|
||||
// }
|
||||
|
||||
return policyInfos
|
||||
// return policyInfos
|
||||
}
|
||||
|
||||
func applyPolicy(client *client.Client, policy *kyverno.Policy, res resourceInfo) (info.PolicyInfo, error) {
|
||||
var policyInfo info.PolicyInfo
|
||||
glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
rawResource, err := res.Resource.MarshalJSON()
|
||||
if err != nil {
|
||||
return policyInfo, err
|
||||
}
|
||||
// Mutate
|
||||
mruleInfos, err := mutation(policy, rawResource, res.Gvk)
|
||||
policyInfo.AddRuleInfos(mruleInfos)
|
||||
if err != nil {
|
||||
return policyInfo, err
|
||||
}
|
||||
// Validation
|
||||
//TODO check by value or pointer
|
||||
vruleInfos, err := Validate(*policy, rawResource, *res.Gvk)
|
||||
if err != nil {
|
||||
return policyInfo, err
|
||||
}
|
||||
policyInfo.AddRuleInfos(vruleInfos)
|
||||
policyInfo = info.NewPolicyInfo(policy.Name, res.Gvk.Kind, res.Resource.GetName(), res.Resource.GetNamespace(), policy.Spec.ValidationFailureAction)
|
||||
// func applyPolicy(client *client.Client, policy *kyverno.Policy, res resourceInfo) (info.PolicyInfo, error) {
|
||||
// var policyInfo info.PolicyInfo
|
||||
// glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
// rawResource, err := res.Resource.MarshalJSON()
|
||||
// if err != nil {
|
||||
// return policyInfo, err
|
||||
// }
|
||||
// // Mutate
|
||||
// mruleInfos, err := mutation(policy, rawResource, res.Gvk)
|
||||
// policyInfo.AddRuleInfos(mruleInfos)
|
||||
// if err != nil {
|
||||
// return policyInfo, err
|
||||
// }
|
||||
// // Validation
|
||||
// //TODO check by value or pointer
|
||||
// vruleInfos, err := Validate(*policy, rawResource, *res.Gvk)
|
||||
// if err != nil {
|
||||
// return policyInfo, err
|
||||
// }
|
||||
// policyInfo.AddRuleInfos(vruleInfos)
|
||||
// policyInfo = info.NewPolicyInfo(policy.Name, res.Gvk.Kind, res.Resource.GetName(), res.Resource.GetNamespace(), policy.Spec.ValidationFailureAction)
|
||||
|
||||
if res.Gvk.Kind == "Namespace" {
|
||||
// if res.Gvk.Kind == "Namespace" {
|
||||
|
||||
// Generation
|
||||
gruleInfos := Generate(client, policy, res.Resource)
|
||||
policyInfo.AddRuleInfos(gruleInfos)
|
||||
}
|
||||
// // Generation
|
||||
// gruleInfos := Generate(client, policy, res.Resource)
|
||||
// policyInfo.AddRuleInfos(gruleInfos)
|
||||
// }
|
||||
|
||||
return policyInfo, nil
|
||||
}
|
||||
// return policyInfo, nil
|
||||
// }
|
||||
|
||||
func mutation(p *kyverno.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
|
||||
patches, ruleInfos := Mutate(*p, rawResource, *gvk)
|
||||
if len(ruleInfos) == 0 {
|
||||
// no rules were processed
|
||||
return nil, nil
|
||||
}
|
||||
// if there are any errors return
|
||||
for _, r := range ruleInfos {
|
||||
if !r.IsSuccessful() {
|
||||
return ruleInfos, nil
|
||||
}
|
||||
}
|
||||
// if there are no patches // for overlay
|
||||
if len(patches) == 0 {
|
||||
return ruleInfos, nil
|
||||
}
|
||||
// option 2: (original Resource + patch) compare with (original resource)
|
||||
mergePatches := JoinPatches(patches)
|
||||
// merge the patches
|
||||
patch, err := jsonpatch.DecodePatch(mergePatches)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// apply the patches returned by mutate to the original resource
|
||||
patchedResource, err := patch.Apply(rawResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// compare (original Resource + patch) vs (original resource)
|
||||
// to verify if they are equal
|
||||
ruleInfo := info.NewRuleInfo("over-all mutation", info.Mutation)
|
||||
if !jsonpatch.Equal(patchedResource, rawResource) {
|
||||
//resource does not match so there was a mutation rule violated
|
||||
// TODO : check the rule name "mutation rules"
|
||||
ruleInfo.Fail()
|
||||
ruleInfo.Add("resource does not satisfy mutation rules")
|
||||
} else {
|
||||
ruleInfo.Add("resource satisfys the mutation rule")
|
||||
}
|
||||
ruleInfos = append(ruleInfos, ruleInfo)
|
||||
return ruleInfos, nil
|
||||
}
|
||||
// func mutation(p *kyverno.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
|
||||
// patches, ruleInfos := Mutate(*p, rawResource, *gvk)
|
||||
// if len(ruleInfos) == 0 {
|
||||
// // no rules were processed
|
||||
// return nil, nil
|
||||
// }
|
||||
// // if there are any errors return
|
||||
// for _, r := range ruleInfos {
|
||||
// if !r.IsSuccessful() {
|
||||
// return ruleInfos, nil
|
||||
// }
|
||||
// }
|
||||
// // if there are no patches // for overlay
|
||||
// if len(patches) == 0 {
|
||||
// return ruleInfos, nil
|
||||
// }
|
||||
// // option 2: (original Resource + patch) compare with (original resource)
|
||||
// mergePatches := JoinPatches(patches)
|
||||
// // merge the patches
|
||||
// patch, err := jsonpatch.DecodePatch(mergePatches)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// // apply the patches returned by mutate to the original resource
|
||||
// patchedResource, err := patch.Apply(rawResource)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// // compare (original Resource + patch) vs (original resource)
|
||||
// // to verify if they are equal
|
||||
// ruleInfo := info.NewRuleInfo("over-all mutation", info.Mutation)
|
||||
// if !jsonpatch.Equal(patchedResource, rawResource) {
|
||||
// //resource does not match so there was a mutation rule violated
|
||||
// // TODO : check the rule name "mutation rules"
|
||||
// ruleInfo.Fail()
|
||||
// ruleInfo.Add("resource does not satisfy mutation rules")
|
||||
// } else {
|
||||
// ruleInfo.Add("resource satisfys the mutation rule")
|
||||
// }
|
||||
// ruleInfos = append(ruleInfos, ruleInfo)
|
||||
// return ruleInfos, nil
|
||||
// }
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
)
|
||||
|
||||
//Generate apply generation rules on a resource
|
||||
func Generate(client *client.Client, policy *kyverno.Policy, ns unstructured.Unstructured) []*info.RuleInfo {
|
||||
ris := []*info.RuleInfo{}
|
||||
func Generate(client *client.Client, policy *kyverno.Policy, ns unstructured.Unstructured) []info.RuleInfo {
|
||||
ris := []info.RuleInfo{}
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.Generation == (kyverno.Generation{}) {
|
||||
continue
|
||||
|
|
|
@ -6,20 +6,15 @@ import (
|
|||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// Mutate performs mutation. Overlay first and then mutation patches
|
||||
//TODO: check if gvk needs to be passed or can be set in resource
|
||||
func Mutate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, []*info.RuleInfo) {
|
||||
func Mutate(policy kyverno.Policy, resource unstructured.Unstructured) ([][]byte, []info.RuleInfo) {
|
||||
//TODO: convert rawResource to unstructured to avoid unmarhalling all the time for get some resource information
|
||||
//TODO: pass unstructured instead of rawResource ?
|
||||
resource, err := convertToUnstructured(rawResource)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to convert raw resource to unstructured: %v", err)
|
||||
}
|
||||
var patches [][]byte
|
||||
var ruleInfos []*info.RuleInfo
|
||||
var ruleInfos []info.RuleInfo
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) {
|
||||
|
@ -29,7 +24,7 @@ func Mutate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKi
|
|||
// 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, gvk)
|
||||
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
|
||||
|
@ -39,7 +34,7 @@ func Mutate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKi
|
|||
|
||||
// Process Overlay
|
||||
if rule.Mutation.Overlay != nil {
|
||||
oPatches, err := processOverlay(resource, rule, rawResource)
|
||||
oPatches, err := processOverlay(resource, rule)
|
||||
if err == nil {
|
||||
if len(oPatches) == 0 {
|
||||
// if array elements dont match then we skip(nil patch, no error)
|
||||
|
@ -66,7 +61,7 @@ func Mutate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKi
|
|||
|
||||
// Process Patches
|
||||
if len(rule.Mutation.Patches) != 0 {
|
||||
jsonPatches, errs := processPatches(rule, rawResource)
|
||||
jsonPatches, errs := processPatches(resource, rule)
|
||||
if len(errs) > 0 {
|
||||
ruleInfo.Fail()
|
||||
for _, err := range errs {
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
// ProcessOverlay handles validating admission request
|
||||
// Checks the target resources for rules defined in the policy
|
||||
func processOverlay(resourceUnstr *unstructured.Unstructured, rule kyverno.Rule, rawResource []byte) ([][]byte, error) {
|
||||
func processOverlay(resourceUnstr unstructured.Unstructured, rule kyverno.Rule) ([][]byte, error) {
|
||||
|
||||
//TODO check if there is better solution
|
||||
resourceRaw, err := resourceUnstr.MarshalJSON()
|
||||
|
|
|
@ -3,9 +3,11 @@ package engine
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
|
@ -13,7 +15,15 @@ import (
|
|||
|
||||
// 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 kyverno.Rule, resource []byte) (allPatches [][]byte, errs []error) {
|
||||
func processPatches(resourceUnstr unstructured.Unstructured, rule kyverno.Rule) (allPatches [][]byte, errs []error) {
|
||||
//TODO check if there is better solution
|
||||
resource, err := resourceUnstr.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to marshal resource : %v", err)
|
||||
errs = append(errs, fmt.Errorf("unable to marshal resource : %v", err))
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
if len(resource) == 0 {
|
||||
errs = append(errs, errors.New("Source document for patching is empty"))
|
||||
return nil, errs
|
||||
|
|
|
@ -150,11 +150,11 @@ func excludeNamespaces(namespaces []string, excludeNs string) []string {
|
|||
}
|
||||
|
||||
//MatchesResourceDescription checks if the resource matches resource desription of the rule or not
|
||||
func MatchesResourceDescription(resource *unstructured.Unstructured, rule kyverno.Rule, gvk metav1.GroupVersionKind) bool {
|
||||
func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno.Rule) bool {
|
||||
matches := rule.MatchResources.ResourceDescription
|
||||
exclude := rule.ExcludeResources.ResourceDescription
|
||||
|
||||
if !findKind(matches.Kinds, gvk.Kind) {
|
||||
if !findKind(matches.Kinds, resource.GetKind()) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -12,30 +12,30 @@ import (
|
|||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// Validate handles validating admission request
|
||||
// Checks the target resources for rules defined in the policy
|
||||
func Validate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
|
||||
func Validate(policy kyverno.Policy, resource unstructured.Unstructured) ([]info.RuleInfo, error) {
|
||||
//TODO: convert rawResource to unstructured to avoid unmarhalling all the time for get some resource information
|
||||
//TODO: pass unstructured instead of rawResource ?
|
||||
resourceUnstr, err := convertToUnstructured(rawResource)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to convert raw resource to unstructured: %v", err)
|
||||
}
|
||||
resourceRaw, err := resourceUnstr.MarshalJSON()
|
||||
// resourceUnstr, err := convertToUnstructured(rawResource)
|
||||
// if err != nil {
|
||||
// glog.Errorf("unable to convert raw resource to unstructured: %v", err)
|
||||
// }
|
||||
resourceRaw, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to marshal resource : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
var resource interface{}
|
||||
if err := json.Unmarshal(resourceRaw, &resource); err != nil {
|
||||
var resourceInt interface{}
|
||||
if err := json.Unmarshal(resourceRaw, &resourceInt); err != nil {
|
||||
glog.V(4).Infof("unable to unmarshal resource : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ruleInfos []*info.RuleInfo
|
||||
var ruleInfos []info.RuleInfo
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
|
||||
|
@ -45,21 +45,21 @@ func Validate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersion
|
|||
// 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(resourceUnstr, rule, gvk)
|
||||
ok := MatchesResourceDescription(resource, rule)
|
||||
if !ok {
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule ", resourceUnstr.GetNamespace(), resourceUnstr.GetName())
|
||||
glog.V(4).Infof("resource %s/%s does not satisfy the resource description for the rule ", resource.GetNamespace(), resource.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
ruleInfo := info.NewRuleInfo(rule.Name, info.Validation)
|
||||
|
||||
err := validateResourceWithPattern(resource, rule.Validation.Pattern)
|
||||
err := validateResourceWithPattern(resourceInt, rule.Validation.Pattern)
|
||||
if err != nil {
|
||||
ruleInfo.Fail()
|
||||
ruleInfo.Addf("Failed to apply pattern: %v.", err)
|
||||
} else {
|
||||
ruleInfo.Add("Pattern succesfully validated")
|
||||
glog.V(4).Infof("pattern validated succesfully on resource %s/%s", resourceUnstr.GetNamespace(), resourceUnstr.GetName())
|
||||
glog.V(4).Infof("pattern validated succesfully on resource %s/%s", resource.GetNamespace(), resource.GetName())
|
||||
}
|
||||
ruleInfos = append(ruleInfos, ruleInfo)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ type PolicyInfo struct {
|
|||
RNamespace string
|
||||
//TODO: add check/enum for types
|
||||
ValidationFailureAction string // BlockChanges, ReportViolation
|
||||
Rules []*RuleInfo
|
||||
Rules []RuleInfo
|
||||
success bool
|
||||
}
|
||||
|
||||
|
@ -135,8 +135,8 @@ func (ri *RuleInfo) GetErrorString() string {
|
|||
}
|
||||
|
||||
//NewRuleInfo creates a new RuleInfo
|
||||
func NewRuleInfo(ruleName string, ruleType RuleType) *RuleInfo {
|
||||
return &RuleInfo{
|
||||
func NewRuleInfo(ruleName string, ruleType RuleType) RuleInfo {
|
||||
return RuleInfo{
|
||||
Name: ruleName,
|
||||
Msgs: []string{},
|
||||
RuleType: ruleType,
|
||||
|
@ -165,7 +165,7 @@ func (ri *RuleInfo) Addf(msg string, args ...interface{}) {
|
|||
}
|
||||
|
||||
//RulesSuccesfuly check if the any rule has failed or not
|
||||
func RulesSuccesfuly(rules []*RuleInfo) bool {
|
||||
func RulesSuccesfuly(rules []RuleInfo) bool {
|
||||
for _, r := range rules {
|
||||
if !r.success {
|
||||
return false
|
||||
|
@ -175,7 +175,7 @@ func RulesSuccesfuly(rules []*RuleInfo) bool {
|
|||
}
|
||||
|
||||
//AddRuleInfos sets the rule information
|
||||
func (pi *PolicyInfo) AddRuleInfos(rules []*RuleInfo) {
|
||||
func (pi *PolicyInfo) AddRuleInfos(rules []RuleInfo) {
|
||||
if rules == nil {
|
||||
return
|
||||
}
|
||||
|
|
93
pkg/policy/apply.go
Normal file
93
pkg/policy/apply.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/golang/glog"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// applyPolicy applies policy on a resource
|
||||
//TODO: generation rules
|
||||
func applyPolicy(policy kyverno.Policy, resource unstructured.Unstructured) (info.PolicyInfo, error) {
|
||||
startTime := time.Now()
|
||||
glog.V(4).Infof("Started apply policy %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), startTime)
|
||||
defer func() {
|
||||
glog.V(4).Infof("Finished applying %s on resource %s/%s/%s (%v)", policy.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), time.Since(startTime))
|
||||
}()
|
||||
// glog.V(4).Infof("apply policy %s with resource version %s on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||
var policyInfo info.PolicyInfo
|
||||
//MUTATION
|
||||
mruleInfos, err := mutation(policy, resource)
|
||||
policyInfo.AddRuleInfos(mruleInfos)
|
||||
if err != nil {
|
||||
return policyInfo, err
|
||||
}
|
||||
|
||||
//VALIDATION
|
||||
vruleInfos, err := engine.Validate(policy, resource)
|
||||
policyInfo.AddRuleInfos(vruleInfos)
|
||||
if err != nil {
|
||||
return policyInfo, err
|
||||
}
|
||||
|
||||
//TODO: GENERATION
|
||||
return policyInfo, nil
|
||||
}
|
||||
|
||||
func mutation(policy kyverno.Policy, resource unstructured.Unstructured) ([]info.RuleInfo, error) {
|
||||
patches, ruleInfos := engine.Mutate(policy, resource)
|
||||
if len(ruleInfos) == 0 {
|
||||
//no rules processed
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for _, r := range ruleInfos {
|
||||
if !r.IsSuccessful() {
|
||||
// no failures while processing rule
|
||||
return ruleInfos, nil
|
||||
}
|
||||
}
|
||||
if len(patches) == 0 {
|
||||
// no patches for the resources
|
||||
// either there were failures or the overlay already was satisfied
|
||||
return ruleInfos, nil
|
||||
}
|
||||
|
||||
// (original resource + patch) == (original resource)
|
||||
mergePatches := utils.JoinPatches(patches)
|
||||
patch, err := jsonpatch.DecodePatch(mergePatches)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawResource, err := resource.MarshalJSON()
|
||||
if err != nil {
|
||||
glog.V(4).Infof("unable to marshal resource : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// apply the patches returned by mutate to the original resource
|
||||
patchedResource, err := patch.Apply(rawResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//TODO: this will be removed after the support for patching for each rule
|
||||
ruleInfo := info.NewRuleInfo("over-all mutation", info.Mutation)
|
||||
|
||||
if !jsonpatch.Equal(patchedResource, rawResource) {
|
||||
//resource does not match so there was a mutation rule violated
|
||||
// TODO : check the rule name "mutation rules"
|
||||
ruleInfo.Fail()
|
||||
ruleInfo.Add("resource does not satisfy mutation rules")
|
||||
} else {
|
||||
ruleInfo.Add("resource satisfys the mutation rule")
|
||||
}
|
||||
|
||||
ruleInfos = append(ruleInfos, ruleInfo)
|
||||
return ruleInfos, nil
|
||||
}
|
|
@ -397,7 +397,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
|||
return err
|
||||
}
|
||||
// process policies on existing resources
|
||||
pc.processExistingResources(p)
|
||||
pc.processExistingResources(*p)
|
||||
|
||||
return pc.syncStatusOnly(p, pvList)
|
||||
}
|
||||
|
|
|
@ -8,12 +8,13 @@ import (
|
|||
"github.com/minio/minio/pkg/wildcard"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) processExistingResources(policy *kyverno.Policy) {
|
||||
func (pc *PolicyController) processExistingResources(policy kyverno.Policy) {
|
||||
// Parse through all the resources
|
||||
// drops the cache after configured rebuild time
|
||||
pc.rm.Drop()
|
||||
|
@ -23,17 +24,27 @@ func (pc *PolicyController) processExistingResources(policy *kyverno.Policy) {
|
|||
for _, resource := range resourceMap {
|
||||
// pre-processing, check if the policy and resource version has been processed before
|
||||
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
|
||||
glog.V(4).Infof("policy %s with resource versio %s already processed on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||
glog.V(4).Infof("policy %s with resource version %s already processed on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||
continue
|
||||
}
|
||||
// apply the policy on each
|
||||
glog.V(4).Infof("apply policy %s with resource version %s on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||
applyPolicyOnResource(policy, resource)
|
||||
// post-processing, register the resource as processed
|
||||
pc.rm.RegisterResource(policy.GetName(), policy.GetResourceVersion(), resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
|
||||
}
|
||||
}
|
||||
|
||||
func listResources(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) map[string]unstructured.Unstructured {
|
||||
func applyPolicyOnResource(policy kyverno.Policy, resource unstructured.Unstructured) *info.PolicyInfo {
|
||||
policyInfo, err := applyPolicy(policy, resource)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to process policy %s on resource %s/%s/%s: %v", policy.GetName(), resource.GetKind(), resource.GetNamespace(), resource.GetName(), err)
|
||||
return nil
|
||||
}
|
||||
return &policyInfo
|
||||
}
|
||||
|
||||
func listResources(client *client.Client, policy kyverno.Policy, filterK8Resources []utils.K8Resource) map[string]unstructured.Unstructured {
|
||||
// key uid
|
||||
resourceMap := map[string]unstructured.Unstructured{}
|
||||
|
||||
|
|
|
@ -187,3 +187,21 @@ func subsetSlice(a, b []interface{}) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// JoinPatches joins array of serialized JSON patches to the single JSONPatch array
|
||||
func JoinPatches(patches [][]byte) []byte {
|
||||
var result []byte
|
||||
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 {
|
||||
result = append(result, []byte(",\n")...)
|
||||
}
|
||||
}
|
||||
result = append(result, []byte("\n]")...)
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func Contains(list []string, element string) bool {
|
||||
|
@ -74,3 +77,14 @@ func ParseKinds(list string) []K8Resource {
|
|||
}
|
||||
return resources
|
||||
}
|
||||
|
||||
//ConvertToUnstructured coverts a raw resource into unstructured struct
|
||||
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
|
||||
resource := &unstructured.Unstructured{}
|
||||
err := resource.UnmarshalJSON(data)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to unmarshall resource: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return resource, nil
|
||||
}
|
||||
|
|
|
@ -51,8 +51,17 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
resource.GetKind(), resource.GetNamespace(), resource.GetName(), request.UID, request.Operation)
|
||||
glog.V(4).Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
|
||||
// resource, err := utils.ConvertToUnstructured(request.Object.Raw)
|
||||
// if err != nil {
|
||||
// glog.Errorf("unable to process policy %s resource %v: %v", policy.GetName(), request.Resource, err)
|
||||
// continue
|
||||
// }
|
||||
//TODO: check if the GVK information is present in the request of we set it explicity here ?
|
||||
glog.V(4).Infof("GVK is %v", resource.GroupVersionKind())
|
||||
// resource.SetGroupVersionKind(schema.GroupVersionKind{Group: request.Kind.Group, Version: request.Kind.Version, Kind: request.Kind.Kind})
|
||||
//TODO: passing policy value as we dont wont to modify the policy
|
||||
policyPatches, ruleInfos := engine.Mutate(*policy, request.Object.Raw, request.Kind)
|
||||
|
||||
policyPatches, ruleInfos := engine.Mutate(*policy, *resource)
|
||||
policyInfo.AddRuleInfos(ruleInfos)
|
||||
policyInfos = append(policyInfos, policyInfo)
|
||||
if !policyInfo.IsSuccessful() {
|
||||
|
|
|
@ -52,7 +52,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
|
||||
glog.V(4).Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
|
||||
ruleInfos, err := engine.Validate(*policy, request.Object.Raw, request.Kind)
|
||||
ruleInfos, err := engine.Validate(*policy, *resource)
|
||||
if err != nil {
|
||||
// This is not policy error
|
||||
// but if unable to parse request raw resource
|
||||
|
|
Loading…
Add table
Reference in a new issue