1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-29 10:55:05 +00:00

527 redesigned implementation so that package variables are not used across packages

This commit is contained in:
shravan 2020-03-04 15:45:20 +05:30
parent 38b92a0d34
commit 6206852262
11 changed files with 128 additions and 192 deletions

View file

@ -5,8 +5,6 @@ import (
"fmt"
"time"
"github.com/nirmata/kyverno/pkg/policyStatus"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
dclient "github.com/nirmata/kyverno/pkg/dclient"
@ -127,7 +125,7 @@ func (c *Controller) applyGeneratePolicy(policyContext engine.PolicyContext, gr
}
if gr.Status.State == "" {
c.policyStatus.Listener <- &generateSyncStats{
c.policyStatus.Listener <- generateSyncStats{
policyName: policy.Name,
ruleNameToProcessingTime: ruleNameToProcessingTime,
}
@ -141,15 +139,11 @@ type generateSyncStats struct {
ruleNameToProcessingTime map[string]time.Duration
}
func (vc *generateSyncStats) UpdateStatus(s *policyStatus.Sync) {
s.Cache.Mutex.Lock()
status, exist := s.Cache.Data[vc.policyName]
if !exist {
policy, _ := s.PolicyStore.Get(vc.policyName)
if policy != nil {
status = policy.Status
}
}
func (vc generateSyncStats) PolicyName() string {
return vc.policyName
}
func (vc generateSyncStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {
for i := range status.Rules {
if executionTime, exist := vc.ruleNameToProcessingTime[status.Rules[i].Name]; exist {
@ -164,8 +158,7 @@ func (vc *generateSyncStats) UpdateStatus(s *policyStatus.Sync) {
}
}
s.Cache.Data[vc.policyName] = status
s.Cache.Mutex.Unlock()
return status
}
func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString string, averageOver int64) time.Duration {

View file

@ -4,54 +4,49 @@ import (
"encoding/json"
"reflect"
"testing"
"time"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/policyStatus"
)
type dummyStore struct {
}
func (d *dummyStore) Get(policyName string) (*v1.ClusterPolicy, error) {
return &v1.ClusterPolicy{}, nil
}
func Test_Stats(t *testing.T) {
testCase := struct {
generatedCountStats []v1.GenerateRequest
expectedOutput []byte
generatedSyncStats []generateSyncStats
expectedOutput []byte
existingStatus map[string]v1.PolicyStatus
}{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"","resourcesGeneratedCount":1},"policy2":{"averageExecutionTime":"","resourcesGeneratedCount":1}}`),
generatedCountStats: []v1.GenerateRequest{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"","resourcesGeneratedCount":2,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"23ns","resourcesGeneratedCount":1},{"ruleName":"rule2","averageExecutionTime":"44ns","resourcesGeneratedCount":1},{"ruleName":"rule3"}]}}`),
generatedSyncStats: []generateSyncStats{
{
Spec: v1.GenerateRequestSpec{
Policy: "policy1",
},
Status: v1.GenerateRequestStatus{
GeneratedResources: make([]v1.ResourceSpec, 1),
policyName: "policy1",
ruleNameToProcessingTime: map[string]time.Duration{
"rule1": time.Nanosecond * 23,
"rule2": time.Nanosecond * 44,
},
},
{
Spec: v1.GenerateRequestSpec{
Policy: "policy2",
},
Status: v1.GenerateRequestStatus{
GeneratedResources: make([]v1.ResourceSpec, 1),
},
existingStatus: map[string]v1.PolicyStatus{
"policy1": {
Rules: []v1.RuleStats{
{
Name: "rule1",
},
{
Name: "rule2",
},
{
Name: "rule3",
},
},
},
},
}
s := policyStatus.NewSync(nil, &dummyStore{})
for _, generateCountStat := range testCase.generatedCountStats {
receiver := &generateSyncStats{
generateRequest: generateCountStat,
}
receiver.UpdateStatus(s)
for _, generateSyncStat := range testCase.generatedSyncStats {
testCase.existingStatus[generateSyncStat.PolicyName()] = generateSyncStat.UpdateStatus(testCase.existingStatus[generateSyncStat.PolicyName()])
}
output, _ := json.Marshal(s.Cache.Data)
output, _ := json.Marshal(testCase.existingStatus)
if !reflect.DeepEqual(output, testCase.expectedOutput) {
t.Errorf("\n\nTestcase has failed\nExpected:\n%v\nGot:\n%v\n\n", string(testCase.expectedOutput), string(output))
}

View file

@ -14,7 +14,8 @@ import (
)
type statusUpdater interface {
UpdateStatus(s *Sync)
PolicyName() string
UpdateStatus(status v1.PolicyStatus) v1.PolicyStatus
}
type policyStore interface {
@ -22,25 +23,25 @@ type policyStore interface {
}
type Sync struct {
Cache *cache
cache *cache
Listener chan statusUpdater
client *versioned.Clientset
PolicyStore policyStore
policyStore policyStore
}
type cache struct {
Mutex sync.RWMutex
Data map[string]v1.PolicyStatus
mutex sync.RWMutex
data map[string]v1.PolicyStatus
}
func NewSync(c *versioned.Clientset, p policyStore) *Sync {
return &Sync{
Cache: &cache{
Mutex: sync.RWMutex{},
Data: make(map[string]v1.PolicyStatus),
cache: &cache{
mutex: sync.RWMutex{},
data: make(map[string]v1.PolicyStatus),
},
client: c,
PolicyStore: p,
policyStore: p,
Listener: make(chan statusUpdater, 20),
}
}
@ -58,7 +59,19 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
for {
select {
case statusUpdater := <-s.Listener:
statusUpdater.UpdateStatus(s)
s.cache.mutex.Lock()
status, exist := s.cache.data[statusUpdater.PolicyName()]
if !exist {
policy, _ := s.policyStore.Get(statusUpdater.PolicyName())
if policy != nil {
status = policy.Status
}
}
s.cache.data[statusUpdater.PolicyName()] = statusUpdater.UpdateStatus(status)
s.cache.mutex.Unlock()
case <-stopCh:
return
}
@ -66,24 +79,24 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
}
func (s *Sync) updatePolicyStatus() {
s.Cache.Mutex.Lock()
var nameToStatus = make(map[string]v1.PolicyStatus, len(s.Cache.Data))
for k, v := range s.Cache.Data {
s.cache.mutex.Lock()
var nameToStatus = make(map[string]v1.PolicyStatus, len(s.cache.data))
for k, v := range s.cache.data {
nameToStatus[k] = v
}
s.Cache.Mutex.Unlock()
s.cache.mutex.Unlock()
for policyName, status := range nameToStatus {
policy, err := s.PolicyStore.Get(policyName)
policy, err := s.policyStore.Get(policyName)
if err != nil {
continue
}
policy.Status = status
_, err = s.client.KyvernoV1().ClusterPolicies().UpdateStatus(policy)
if err != nil {
s.Cache.Mutex.Lock()
delete(s.Cache.Data, policyName)
s.Cache.Mutex.Unlock()
s.cache.mutex.Lock()
delete(s.cache.data, policyName)
s.cache.mutex.Unlock()
glog.V(4).Info(err)
}
}

View file

@ -100,7 +100,7 @@ func (cpv *clusterPV) createPV(newPv *kyverno.ClusterPolicyViolation) error {
}
if newPv.Annotations["fromSync"] != "true" {
cpv.policyStatus.Listener <- updatePolicyStatusWithViolationCount(newPv.Spec.Policy, newPv.Spec.ViolatedRules)
cpv.policyStatus.Listener <- violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}
}
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
@ -126,7 +126,7 @@ func (cpv *clusterPV) updatePV(newPv, oldPv *kyverno.ClusterPolicyViolation) err
glog.Infof("cluster policy violation updated for resource %v", newPv.Spec.ResourceSpec)
if newPv.Annotations["fromSync"] != "true" {
cpv.policyStatus.Listener <- updatePolicyStatusWithViolationCount(newPv.Spec.Policy, newPv.Spec.ViolatedRules)
cpv.policyStatus.Listener <- violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}
}
return nil
}

View file

@ -4,8 +4,6 @@ import (
"fmt"
"time"
"github.com/nirmata/kyverno/pkg/policyStatus"
backoff "github.com/cenkalti/backoff"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -79,22 +77,11 @@ type violationCount struct {
violatedRules []v1.ViolatedRule
}
func updatePolicyStatusWithViolationCount(policyName string, violatedRules []kyverno.ViolatedRule) *violationCount {
return &violationCount{
policyName: policyName,
violatedRules: violatedRules,
}
func (vc violationCount) PolicyName() string {
return vc.policyName
}
func (vc *violationCount) UpdateStatus(s *policyStatus.Sync) {
s.Cache.Mutex.Lock()
status, exist := s.Cache.Data[vc.policyName]
if !exist {
policy, _ := s.PolicyStore.Get(vc.policyName)
if policy != nil {
status = policy.Status
}
}
func (vc violationCount) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {
var ruleNameToViolations = make(map[string]int)
for _, rule := range vc.violatedRules {
@ -106,6 +93,5 @@ func (vc *violationCount) UpdateStatus(s *policyStatus.Sync) {
status.Rules[i].ViolationCount += ruleNameToViolations[status.Rules[i].Name]
}
s.Cache.Data[vc.policyName] = status
s.Cache.Mutex.Unlock()
return status
}

View file

@ -99,7 +99,7 @@ func (nspv *namespacedPV) createPV(newPv *kyverno.PolicyViolation) error {
}
if newPv.Annotations["fromSync"] != "true" {
nspv.policyStatus.Listener <- updatePolicyStatusWithViolationCount(newPv.Spec.Policy, newPv.Spec.ViolatedRules)
nspv.policyStatus.Listener <- violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}
}
glog.Infof("policy violation created for resource %v", newPv.Spec.ResourceSpec)
return nil
@ -122,7 +122,7 @@ func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error
}
if newPv.Annotations["fromSync"] != "true" {
nspv.policyStatus.Listener <- updatePolicyStatusWithViolationCount(newPv.Spec.Policy, newPv.Spec.ViolatedRules)
nspv.policyStatus.Listener <- violationCount{policyName: newPv.Spec.Policy, violatedRules: newPv.Spec.ViolatedRules}
}
glog.Infof("namespaced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
return nil

View file

@ -5,26 +5,9 @@ import (
"reflect"
"testing"
"github.com/nirmata/kyverno/pkg/policyStatus"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
)
type dummyStore struct {
}
func (d *dummyStore) Get(policyName string) (*v1.ClusterPolicy, error) {
return &v1.ClusterPolicy{
Status: v1.PolicyStatus{
Rules: []v1.RuleStats{
{
Name: "rule4",
},
},
},
}, nil
}
func Test_Stats(t *testing.T) {
testCase := struct {
violationCountStats []struct {
@ -32,7 +15,24 @@ func Test_Stats(t *testing.T) {
violatedRules []v1.ViolatedRule
}
expectedOutput []byte
existingCache map[string]v1.PolicyStatus
}{
existingCache: map[string]v1.PolicyStatus{
"policy1": {
Rules: []v1.RuleStats{
{
Name: "rule4",
},
},
},
"policy2": {
Rules: []v1.RuleStats{
{
Name: "rule4",
},
},
},
},
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"","violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]},"policy2":{"averageExecutionTime":"","violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]}}`),
violationCountStats: []struct {
policyName string
@ -57,17 +57,17 @@ func Test_Stats(t *testing.T) {
},
}
s := policyStatus.NewSync(nil, &dummyStore{})
policyNameToStatus := testCase.existingCache
for _, violationCountStat := range testCase.violationCountStats {
receiver := &violationCount{
policyName: violationCountStat.policyName,
violatedRules: violationCountStat.violatedRules,
}
receiver.UpdateStatus(s)
policyNameToStatus[receiver.PolicyName()] = receiver.UpdateStatus(policyNameToStatus[receiver.PolicyName()])
}
output, _ := json.Marshal(s.Cache.Data)
output, _ := json.Marshal(policyNameToStatus)
if !reflect.DeepEqual(output, testCase.expectedOutput) {
t.Errorf("\n\nTestcase has failed\nExpected:\n%v\nGot:\n%v\n\n", string(testCase.expectedOutput), string(output))
}

View file

@ -5,8 +5,6 @@ import (
"sort"
"time"
"github.com/nirmata/kyverno/pkg/policyStatus"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -68,7 +66,9 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
if len(engineResponse.PolicyResponse.Rules) > 0 {
// some generate rules do apply to the resource
engineResponses = append(engineResponses, engineResponse)
ws.status.Listener <- updateStatusWithGenerateStats(engineResponse)
ws.status.Listener <- generateStats{
resp: engineResponse,
}
}
}
// Adds Generate Request to a channel(queue size 1000) to generators
@ -115,26 +115,13 @@ type generateStats struct {
resp response.EngineResponse
}
func updateStatusWithGenerateStats(resp response.EngineResponse) *generateStats {
return &generateStats{
resp: resp,
}
func (gs generateStats) PolicyName() string {
return gs.resp.PolicyResponse.Policy
}
func (gs *generateStats) UpdateStatus(s *policyStatus.Sync) {
func (gs generateStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {
if reflect.DeepEqual(response.EngineResponse{}, gs.resp) {
return
}
s.Cache.Mutex.Lock()
status, exist := s.Cache.Data[gs.resp.PolicyResponse.Policy]
if !exist {
if s.PolicyStore != nil {
policy, _ := s.PolicyStore.Get(gs.resp.PolicyResponse.Policy)
if policy != nil {
status = policy.Status
}
}
return status
}
var nameToRule = make(map[string]v1.RuleStats)
@ -180,8 +167,7 @@ func (gs *generateStats) UpdateStatus(s *policyStatus.Sync) {
status.AvgExecutionTime = policyAverageExecutionTime.String()
status.Rules = ruleStats
s.Cache.Data[gs.resp.PolicyResponse.Policy] = status
s.Cache.Mutex.Unlock()
return status
}
func updateAverageTime(newTime time.Duration, oldAverageTimeString string, averageOver int64) time.Duration {

View file

@ -5,8 +5,6 @@ import (
"sort"
"time"
"github.com/nirmata/kyverno/pkg/policyStatus"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -63,7 +61,9 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou
policyContext.Policy = policy
engineResponse := engine.Mutate(policyContext)
engineResponses = append(engineResponses, engineResponse)
ws.status.Listener <- updateStatusWithMutateStats(engineResponse)
ws.status.Listener <- mutateStats{
resp: engineResponse,
}
if !engineResponse.IsSuccesful() {
glog.V(4).Infof("Failed to apply policy %s on resource %s/%s\n", policy.Name, resource.GetNamespace(), resource.GetName())
continue
@ -122,27 +122,13 @@ type mutateStats struct {
resp response.EngineResponse
}
func updateStatusWithMutateStats(resp response.EngineResponse) *mutateStats {
return &mutateStats{
resp: resp,
}
func (ms mutateStats) PolicyName() string {
return ms.resp.PolicyResponse.Policy
}
func (ms *mutateStats) UpdateStatus(s *policyStatus.Sync) {
func (ms mutateStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {
if reflect.DeepEqual(response.EngineResponse{}, ms.resp) {
return
}
s.Cache.Mutex.Lock()
status, exist := s.Cache.Data[ms.resp.PolicyResponse.Policy]
if !exist {
if s.PolicyStore != nil {
policy, _ := s.PolicyStore.Get(ms.resp.PolicyResponse.Policy)
if policy != nil {
status = policy.Status
}
}
return status
}
var nameToRule = make(map[string]v1.RuleStats)
@ -190,6 +176,5 @@ func (ms *mutateStats) UpdateStatus(s *policyStatus.Sync) {
status.AvgExecutionTime = policyAverageExecutionTime.String()
status.Rules = ruleStats
s.Cache.Data[ms.resp.PolicyResponse.Policy] = status
s.Cache.Mutex.Unlock()
return status
}

View file

@ -8,16 +8,8 @@ import (
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/policyStatus"
)
type dummyStore struct {
}
func (d *dummyStore) Get(policyName string) (*v1.ClusterPolicy, error) {
return &v1.ClusterPolicy{}, nil
}
func Test_GenerateStats(t *testing.T) {
testCase := struct {
generateStats []response.EngineResponse
@ -70,16 +62,16 @@ func Test_GenerateStats(t *testing.T) {
},
}
s := policyStatus.NewSync(nil, &dummyStore{})
policyNameToStatus := map[string]v1.PolicyStatus{}
for _, generateStat := range testCase.generateStats {
receiver := &generateStats{
receiver := generateStats{
resp: generateStat,
}
receiver.UpdateStatus(s)
policyNameToStatus[receiver.PolicyName()] = receiver.UpdateStatus(policyNameToStatus[receiver.PolicyName()])
}
output, _ := json.Marshal(s.Cache.Data)
output, _ := json.Marshal(policyNameToStatus)
if !reflect.DeepEqual(output, testCase.expectedOutput) {
t.Errorf("\n\nTestcase has failed\nExpected:\n%v\nGot:\n%v\n\n", string(testCase.expectedOutput), string(output))
}
@ -137,15 +129,15 @@ func Test_MutateStats(t *testing.T) {
},
}
s := policyStatus.NewSync(nil, &dummyStore{})
policyNameToStatus := map[string]v1.PolicyStatus{}
for _, mutateStat := range testCase.mutateStats {
receiver := &mutateStats{
receiver := mutateStats{
resp: mutateStat,
}
receiver.UpdateStatus(s)
policyNameToStatus[receiver.PolicyName()] = receiver.UpdateStatus(policyNameToStatus[receiver.PolicyName()])
}
output, _ := json.Marshal(s.Cache.Data)
output, _ := json.Marshal(policyNameToStatus)
if !reflect.DeepEqual(output, testCase.expectedOutput) {
t.Errorf("\n\nTestcase has failed\nExpected:\n%v\nGot:\n%v\n\n", string(testCase.expectedOutput), string(output))
}
@ -204,15 +196,15 @@ func Test_ValidateStats(t *testing.T) {
},
}
s := policyStatus.NewSync(nil, &dummyStore{})
policyNameToStatus := map[string]v1.PolicyStatus{}
for _, validateStat := range testCase.validateStats {
receiver := &validateStats{
receiver := validateStats{
resp: validateStat,
}
receiver.UpdateStatus(s)
policyNameToStatus[receiver.PolicyName()] = receiver.UpdateStatus(policyNameToStatus[receiver.PolicyName()])
}
output, _ := json.Marshal(s.Cache.Data)
output, _ := json.Marshal(policyNameToStatus)
if !reflect.DeepEqual(output, testCase.expectedOutput) {
t.Errorf("\n\nTestcase has failed\nExpected:\n%v\nGot:\n%v\n\n", string(testCase.expectedOutput), string(output))
}

View file

@ -5,8 +5,6 @@ import (
"sort"
"time"
"github.com/nirmata/kyverno/pkg/policyStatus"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
@ -73,7 +71,9 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
continue
}
engineResponses = append(engineResponses, engineResponse)
ws.status.Listener <- updateStatusWithValidateStats(engineResponse)
ws.status.Listener <- validateStats{
resp: engineResponse,
}
if !engineResponse.IsSuccesful() {
glog.V(4).Infof("Failed to apply policy %s on resource %s/%s\n", policy.Name, newR.GetNamespace(), newR.GetName())
continue
@ -117,26 +117,13 @@ type validateStats struct {
resp response.EngineResponse
}
func updateStatusWithValidateStats(resp response.EngineResponse) *validateStats {
return &validateStats{
resp: resp,
}
func (vs validateStats) PolicyName() string {
return vs.resp.PolicyResponse.Policy
}
func (vs *validateStats) UpdateStatus(s *policyStatus.Sync) {
func (vs validateStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {
if reflect.DeepEqual(response.EngineResponse{}, vs.resp) {
return
}
s.Cache.Mutex.Lock()
status, exist := s.Cache.Data[vs.resp.PolicyResponse.Policy]
if !exist {
if s.PolicyStore != nil {
policy, _ := s.PolicyStore.Get(vs.resp.PolicyResponse.Policy)
if policy != nil {
status = policy.Status
}
}
return status
}
var nameToRule = make(map[string]v1.RuleStats)
@ -186,6 +173,5 @@ func (vs *validateStats) UpdateStatus(s *policyStatus.Sync) {
status.AvgExecutionTime = policyAverageExecutionTime.String()
status.Rules = ruleStats
s.Cache.Data[vs.resp.PolicyResponse.Policy] = status
s.Cache.Mutex.Unlock()
return status
}