From d758a4ad4539ac8d007dad9deaf7dc8fb616f784 Mon Sep 17 00:00:00 2001 From: shravan Date: Sun, 23 Feb 2020 23:24:18 +0530 Subject: [PATCH] 527 added accurate violation Count --- cmd/kyverno/main.go | 7 ++- pkg/api/kyverno/v1/types.go | 8 +++- pkg/policy/status.go | 86 ++++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 13 deletions(-) diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index ee6644e91c..812337ac9b 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -200,7 +200,12 @@ func main() { glog.Fatalf("Failed registering Admission Webhooks: %v\n", err) } - statusSync := policy.NewStatusSync(pclient, stopCh, policyMetaStore) + statusSync := policy.NewStatusSync( + pclient, + stopCh, + policyMetaStore, + pInformer.Kyverno().V1().ClusterPolicyViolations().Lister(), + pInformer.Kyverno().V1().PolicyViolations().Lister()) // WEBHOOOK // - https server to provide endpoints called based on rules defined in Mutating & Validation webhook configuration diff --git a/pkg/api/kyverno/v1/types.go b/pkg/api/kyverno/v1/types.go index fa29e4be83..22e5f54468 100644 --- a/pkg/api/kyverno/v1/types.go +++ b/pkg/api/kyverno/v1/types.go @@ -231,8 +231,10 @@ type CloneFrom struct { type PolicyStatus struct { // average time required to process the policy rules on a resource AvgExecutionTime string `json:"averageExecutionTime"` - // Count of rules that failed + // number of violations related to the policy ViolationCount int `json:"violationCount,omitempty"` + // Count of rules that failed + RulesFailedCount int `json:"rulesFailedCount,omitempty"` // Count of rules that were applied RulesAppliedCount int `json:"rulesAppliedCount,omitempty"` // Count of resources that were blocked for failing a validate, across all rules @@ -249,8 +251,10 @@ type RuleStats struct { Name string `json:"ruleName"` // average time require to process the rule ExecutionTime string `json:"averageExecutionTime,omitempty"` - // Count of rules that failed + // number of violations related to this rule ViolationCount int `json:"violationCount,omitempty"` + // Count of rules that failed + FailedCount int `json:"failedCount,omitempty"` // Count of rules that were applied AppliedCount int `json:"appliedCount,omitempty"` // Count of resources for whom update/create api requests were blocked as the resource did not satisfy the policy rules diff --git a/pkg/policy/status.go b/pkg/policy/status.go index a3061629e2..a46fd74857 100644 --- a/pkg/policy/status.go +++ b/pkg/policy/status.go @@ -6,6 +6,8 @@ import ( "sync" "time" + v12 "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" + "github.com/nirmata/kyverno/pkg/policystore" "github.com/nirmata/kyverno/pkg/engine/response" @@ -27,9 +29,17 @@ type StatSync struct { stop <-chan struct{} client *versioned.Clientset policyStore *policystore.PolicyStore + cpvLister v12.ClusterPolicyViolationLister + pvLister v12.PolicyViolationLister } -func NewStatusSync(client *versioned.Clientset, stopCh <-chan struct{}, pMetaStore *policystore.PolicyStore) *StatSync { +func NewStatusSync( + client *versioned.Clientset, + stopCh <-chan struct{}, + pMetaStore *policystore.PolicyStore, + cpvLister v12.ClusterPolicyViolationLister, + pvLister v12.PolicyViolationLister, +) *StatSync { return &StatSync{ cache: &statusCache{ mu: sync.RWMutex{}, @@ -38,6 +48,8 @@ func NewStatusSync(client *versioned.Clientset, stopCh <-chan struct{}, pMetaSto stop: stopCh, client: client, policyStore: pMetaStore, + cpvLister: cpvLister, + pvLister: pvLister, } } @@ -57,6 +69,10 @@ func (s *StatSync) updateStats() { s.cache.mu.Unlock() for policyName, status := range nameToStatus { + cpvList, _ := s.getClusterPolicyViolationForPolicy(policyName) + pvList, _ := s.getNamespacedPolicyViolationForPolicy(policyName) + updateStatusWithViolationCount(&status, cpvList, pvList) + var policy = &v1.ClusterPolicy{} policy, err := s.policyStore.Get(policyName) if err != nil { @@ -90,7 +106,7 @@ func (s *StatSync) UpdateStatusWithMutateStats(response response.EngineResponse) ruleStat := nameToRule[rule.Name] ruleStat.Name = rule.Name - averageOver := int64(ruleStat.AppliedCount + ruleStat.ViolationCount) + averageOver := int64(ruleStat.AppliedCount + ruleStat.FailedCount) ruleStat.ExecutionTime = updateAverageTime( rule.ProcessingTime, ruleStat.ExecutionTime, @@ -102,8 +118,8 @@ func (s *StatSync) UpdateStatusWithMutateStats(response response.EngineResponse) ruleStat.AppliedCount++ ruleStat.ResourcesMutatedCount++ } else { - policyStatus.ViolationCount++ - ruleStat.ViolationCount++ + policyStatus.RulesFailedCount++ + ruleStat.FailedCount++ } nameToRule[rule.Name] = ruleStat @@ -150,7 +166,7 @@ func (s *StatSync) UpdateStatusWithValidateStats(response response.EngineRespons ruleStat := nameToRule[rule.Name] ruleStat.Name = rule.Name - averageOver := int64(ruleStat.AppliedCount + ruleStat.ViolationCount) + averageOver := int64(ruleStat.AppliedCount + ruleStat.FailedCount) ruleStat.ExecutionTime = updateAverageTime( rule.ProcessingTime, ruleStat.ExecutionTime, @@ -160,8 +176,8 @@ func (s *StatSync) UpdateStatusWithValidateStats(response response.EngineRespons policyStatus.RulesAppliedCount++ ruleStat.AppliedCount++ } else { - policyStatus.ViolationCount++ - ruleStat.ViolationCount++ + policyStatus.RulesFailedCount++ + ruleStat.FailedCount++ if response.PolicyResponse.ValidationFailureAction == "enforce" { policyStatus.ResourcesBlockedCount++ ruleStat.ResourcesBlockedCount++ @@ -212,7 +228,7 @@ func (s *StatSync) UpdateStatusWithGenerateStats(response response.EngineRespons ruleStat := nameToRule[rule.Name] ruleStat.Name = rule.Name - averageOver := int64(ruleStat.AppliedCount + ruleStat.ViolationCount) + averageOver := int64(ruleStat.AppliedCount + ruleStat.FailedCount) ruleStat.ExecutionTime = updateAverageTime( rule.ProcessingTime, ruleStat.ExecutionTime, @@ -222,8 +238,8 @@ func (s *StatSync) UpdateStatusWithGenerateStats(response response.EngineRespons policyStatus.RulesAppliedCount++ ruleStat.AppliedCount++ } else { - policyStatus.ViolationCount++ - ruleStat.ViolationCount++ + policyStatus.RulesFailedCount++ + ruleStat.FailedCount++ } nameToRule[rule.Name] = ruleStat @@ -260,3 +276,53 @@ func updateAverageTime(newTime time.Duration, oldAverageTimeString string, avera newAverageTimeInNanoSeconds := numerator / denominator return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond } + +func (s *StatSync) getClusterPolicyViolationForPolicy(policy string) ([]*v1.ClusterPolicyViolation, error) { + policySelector, err := buildPolicyLabel(policy) + if err != nil { + return nil, err + } + // Get List of cluster policy violation + cpvList, err := s.cpvLister.List(policySelector) + if err != nil { + return nil, err + } + return cpvList, nil +} + +func (s *StatSync) getNamespacedPolicyViolationForPolicy(policy string) ([]*v1.PolicyViolation, error) { + policySelector, err := buildPolicyLabel(policy) + if err != nil { + return nil, err + } + // Get List of cluster policy violation + nspvList, err := s.pvLister.List(policySelector) + if err != nil { + return nil, err + } + return nspvList, nil + +} + +func updateStatusWithViolationCount(status *v1.PolicyStatus, cpvList []*v1.ClusterPolicyViolation, pvList []*v1.PolicyViolation) { + + status.ViolationCount = len(cpvList) + len(pvList) + + var ruleNameToNumberOfViolations = make(map[string]int) + + for _, cpv := range cpvList { + for _, violatedRule := range cpv.Spec.ViolatedRules { + ruleNameToNumberOfViolations[violatedRule.Name]++ + } + } + + for _, pv := range pvList { + for _, violatedRule := range pv.Spec.ViolatedRules { + ruleNameToNumberOfViolations[violatedRule.Name]++ + } + } + + for i, rule := range status.Rules { + status.Rules[i].ViolationCount = ruleNameToNumberOfViolations[rule.Name] + } +}