diff --git a/pkg/api/kyverno/v1alpha1/types.go b/pkg/api/kyverno/v1alpha1/types.go index 5597f97e23..691a0c1f11 100644 --- a/pkg/api/kyverno/v1alpha1/types.go +++ b/pkg/api/kyverno/v1alpha1/types.go @@ -1,6 +1,8 @@ package v1alpha1 import ( + "time" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -89,7 +91,15 @@ type CloneFrom struct { //PolicyStatus provides status for violations type PolicyStatus struct { - Violations int `json:"violations"` + ViolationCount int `json:"violationCount"` + // Count of rules that were applied + RulesAppliedCount int `json:"rulesAppliedCount"` + // Count of resources for whom update/create api requests were blocked as the resoruce did not satisfy the policy rules + ResourcesBlockedCount int `json:"resourcesBlockedCount"` + // average time required to process the policy Mutation rules on a resource + AvgExecutionTimeMutation time.Duration `json:"averageMutationExecutionTime"` + // average time required to process the policy Validation rules on a resource + AvgExecutionTimeValidation time.Duration `json:"averageValidationExecutionTime"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/policy/controller.go b/pkg/policy/controller.go index 0457423250..02cc1c072e 100644 --- a/pkg/policy/controller.go +++ b/pkg/policy/controller.go @@ -119,7 +119,7 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client. pc.rm = NewResourceManager(30) // aggregator - pc.statusAggregator = NewPolicyStatAggregator(kyvernoClient, pInformer.Lister()) + pc.statusAggregator = NewPolicyStatAggregator(kyvernoClient, pInformer) return &pc, nil } diff --git a/pkg/policy/status.go b/pkg/policy/status.go index fe8a77512a..f19961dba5 100644 --- a/pkg/policy/status.go +++ b/pkg/policy/status.go @@ -1,6 +1,7 @@ package policy import ( + "fmt" "reflect" "sync" "time" @@ -8,48 +9,55 @@ import ( "github.com/golang/glog" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1" kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned" + kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1alpha1" kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1alpha1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/tools/cache" ) -type PolicyStatus struct { - // average time required to process the policy rules on a resource - avgExecutionTime time.Duration - // Count of rules that were applied succesfully - rulesAppliedCount int - // Count of resources for whom update/create api requests were blocked as the resoruce did not satisfy the policy rules - resourcesBlockedCount int - // Count of the resource for whom the mutation rules were applied succesfully - resourcesMutatedCount int -} +// type PolicyStatus struct { +// // average time required to process the policy rules on a resource +// avgExecutionTime time.Duration +// // Count of rules that were applied succesfully +// rulesAppliedCount int +// // Count of resources for whom update/create api requests were blocked as the resoruce did not satisfy the policy rules +// resourcesBlockedCount int +// // Count of the resource for whom the mutation rules were applied succesfully +// resourcesMutatedCount int +// } +//PolicyStatusAggregator stores information abt aggregation type PolicyStatusAggregator struct { // time since we start aggregating the stats startTime time.Time // channel to recieve stats ch chan PolicyStat - // update polict status + // update policy status psControl PStatusControlInterface // pLister can list/get policy from the shared informer's store pLister kyvernolister.PolicyLister + // pListerSynced returns true if the Policy store has been synced at least once + pListerSynced cache.InformerSynced // UpdateViolationCount and SendStat can update same policy status // we need to sync the updates using policyName policyUpdateData sync.Map } //NewPolicyStatAggregator returns a new policy status -func NewPolicyStatAggregator(client *kyvernoclient.Clientset, pLister kyvernolister.PolicyLister) *PolicyStatusAggregator { +func NewPolicyStatAggregator(client *kyvernoclient.Clientset, pInformer kyvernoinformer.PolicyInformer) *PolicyStatusAggregator { psa := PolicyStatusAggregator{ startTime: time.Now(), ch: make(chan PolicyStat), } - psa.pLister = pLister + psa.pLister = pInformer.Lister() + psa.pListerSynced = pInformer.Informer().HasSynced psa.psControl = PSControl{Client: client} //TODO: add WaitGroup return &psa } +//Run begins aggregator func (psa *PolicyStatusAggregator) Run(workers int, stopCh <-chan struct{}) { defer utilruntime.HandleCrash() glog.V(4).Info("Started aggregator for policy status stats") @@ -69,7 +77,7 @@ func (psa *PolicyStatusAggregator) aggregate() { for r := range psa.ch { glog.V(4).Infof("recieved policy stats %v", r) if err := psa.updateStats(r); err != nil { - glog.Info("Failed to update stats for policy %s: %v", r.PolicyName, err) + glog.Infof("Failed to update stats for policy %s: %v", r.PolicyName, err) } } @@ -77,32 +85,59 @@ func (psa *PolicyStatusAggregator) aggregate() { func (psa *PolicyStatusAggregator) updateStats(stats PolicyStat) error { func() { - glog.V(4).Infof("lock updates for policy name %s", stats.PolicyName) + glog.V(4).Infof("lock updates for policy %s", stats.PolicyName) // Lock the update for policy psa.policyUpdateData.Store(stats.PolicyName, struct{}{}) }() defer func() { - glog.V(4).Infof("Unlock updates for policy name %s", stats.PolicyName) + glog.V(4).Infof("Unlock updates for policy %s", stats.PolicyName) psa.policyUpdateData.Delete(stats.PolicyName) }() + + // //wait for cache sync + // if !cache.WaitForCacheSync(nil, psa.pListerSynced) { + // glog.Infof("unable to sync cache for policy informer") + // return nil + // } // get policy policy, err := psa.pLister.Get(stats.PolicyName) if err != nil { glog.V(4).Infof("failed to get policy %s. Unable to update violation count: %v", stats.PolicyName, err) return err } + newpolicy := policy + fmt.Println(newpolicy.ResourceVersion) + newpolicy.Status = kyverno.PolicyStatus{} glog.V(4).Infof("updating stats for policy %s", policy.Name) - // update the statistics - // policy.Status - - return nil + // rules applied count + newpolicy.Status.RulesAppliedCount = newpolicy.Status.RulesAppliedCount + stats.RulesAppliedCount + // resource blocked count + if stats.ResourceBlocked { + policy.Status.ResourcesBlockedCount++ + } + var zeroDuration time.Duration + if newpolicy.Status.AvgExecutionTimeMutation != zeroDuration { + // avg execution time for mutation rules + newpolicy.Status.AvgExecutionTimeMutation = (newpolicy.Status.AvgExecutionTimeMutation + stats.MutationExecutionTime) / 2 + } else { + newpolicy.Status.AvgExecutionTimeMutation = stats.MutationExecutionTime + } + if policy.Status.AvgExecutionTimeValidation != zeroDuration { + // avg execution time for validation rules + newpolicy.Status.AvgExecutionTimeValidation = (newpolicy.Status.AvgExecutionTimeValidation + stats.ValidationExecutionTime) / 2 + } else { + newpolicy.Status.AvgExecutionTimeValidation = stats.ValidationExecutionTime + } + return psa.psControl.UpdatePolicyStatus(newpolicy) } +//PolicyStatusInterface provides methods to modify policyStatus type PolicyStatusInterface interface { SendStat(stat PolicyStat) UpdateViolationCount(policyName string, pvList []*kyverno.PolicyViolation) error } +//PolicyStat stored stats for policy type PolicyStat struct { PolicyName string MutationExecutionTime time.Duration @@ -121,12 +156,12 @@ func (psa *PolicyStatusAggregator) SendStat(stat PolicyStat) { //UpdateViolationCount updates the active violation count func (psa *PolicyStatusAggregator) UpdateViolationCount(policyName string, pvList []*kyverno.PolicyViolation) error { func() { - glog.V(4).Infof("lock updates for policy name %s", policyName) + glog.V(4).Infof("lock updates for policy %s", policyName) // Lock the update for policy psa.policyUpdateData.Store(policyName, struct{}{}) }() defer func() { - glog.V(4).Infof("Unlock updates for policy name %s", policyName) + glog.V(4).Infof("Unlock updates for policy %s", policyName) psa.policyUpdateData.Delete(policyName) }() // get policy @@ -139,6 +174,7 @@ func (psa *PolicyStatusAggregator) UpdateViolationCount(policyName string, pvLis newStatus := calculateStatus(pvList) if reflect.DeepEqual(newStatus, policy.Status) { // no update to status + glog.V(4).Infof("no changes in policy violation count for policy %s", policy.Name) return nil } // update status @@ -151,7 +187,7 @@ func (psa *PolicyStatusAggregator) UpdateViolationCount(policyName string, pvLis func calculateStatus(pvList []*kyverno.PolicyViolation) kyverno.PolicyStatus { violationCount := len(pvList) status := kyverno.PolicyStatus{ - Violations: violationCount, + ViolationCount: violationCount, } return status } @@ -166,6 +202,7 @@ type PStatusControlInterface interface { UpdatePolicyStatus(newPolicy *kyverno.Policy) error } +//PSControl allows update for policy status type PSControl struct { Client kyvernoclient.Interface }