1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-07 08:26:53 +00:00
kyverno/pkg/policystatus/main.go

147 lines
3.8 KiB
Go
Raw Normal View History

package policystatus
2020-02-25 20:55:07 +05:30
import (
2020-03-07 16:23:17 +05:30
"encoding/json"
2020-02-25 20:55:07 +05:30
"sync"
"time"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
)
2020-03-07 16:23:17 +05:30
// Policy status implementation works in the following way,
//Currently policy status maintains a cache of the status of
//each policy.
//Every x unit of time the status of policy is updated using
//the data from the cache.
//The sync exposes a listener which accepts a statusUpdater
//interface which dictates how the status should be updated.
//The status is updated by a worker that receives the interface
//on a channel.
//The worker then updates the current status using the methods
//exposed by the interface.
//Current implementation is designed to be threadsafe with optimised
//locking for each policy.
// statusUpdater defines a type to have a method which
//updates the given status
2020-02-29 22:39:27 +05:30
type statusUpdater interface {
PolicyName() string
UpdateStatus(status v1.PolicyStatus) v1.PolicyStatus
2020-02-29 22:39:27 +05:30
}
type policyStore interface {
Get(policyName string) (*v1.ClusterPolicy, error)
}
type Listener chan statusUpdater
func (l Listener) Send(s statusUpdater) {
l <- s
}
2020-03-07 16:23:17 +05:30
// Sync is the object which is used to initialize
//the policyStatus sync, can be considered the parent object
//since it contains access to all the persistant data present
//in this package.
2020-02-25 20:55:07 +05:30
type Sync struct {
cache *cache
Listener Listener
2020-02-25 20:55:07 +05:30
client *versioned.Clientset
policyStore policyStore
2020-02-25 20:55:07 +05:30
}
type cache struct {
2020-03-07 14:56:42 +05:30
dataMu sync.RWMutex
data map[string]v1.PolicyStatus
keyToMutex *keyToMutex
2020-02-25 20:55:07 +05:30
}
2020-02-29 22:39:27 +05:30
func NewSync(c *versioned.Clientset, p policyStore) *Sync {
2020-02-25 20:55:07 +05:30
return &Sync{
cache: &cache{
2020-03-07 14:56:42 +05:30
dataMu: sync.RWMutex{},
data: make(map[string]v1.PolicyStatus),
keyToMutex: newKeyToMutex(),
2020-02-25 20:55:07 +05:30
},
client: c,
policyStore: p,
Listener: make(chan statusUpdater, 20),
2020-02-25 20:55:07 +05:30
}
}
2020-02-29 17:19:00 +05:30
func (s *Sync) Run(workers int, stopCh <-chan struct{}) {
2020-02-25 21:07:00 +05:30
for i := 0; i < workers; i++ {
2020-02-29 17:19:00 +05:30
go s.updateStatusCache(stopCh)
2020-02-25 21:07:00 +05:30
}
2020-02-29 17:19:00 +05:30
wait.Until(s.updatePolicyStatus, 2*time.Second, stopCh)
<-stopCh
2020-02-25 20:55:07 +05:30
}
2020-03-07 16:23:17 +05:30
// updateStatusCache is a worker which updates the current status
//using the statusUpdater interface
2020-02-29 17:19:00 +05:30
func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
2020-02-25 20:55:07 +05:30
for {
select {
2020-02-29 22:39:27 +05:30
case statusUpdater := <-s.Listener:
2020-03-07 14:56:42 +05:30
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Lock()
2020-03-07 14:56:42 +05:30
s.cache.dataMu.RLock()
status, exist := s.cache.data[statusUpdater.PolicyName()]
2020-03-07 14:56:42 +05:30
s.cache.dataMu.RUnlock()
if !exist {
policy, _ := s.policyStore.Get(statusUpdater.PolicyName())
if policy != nil {
status = policy.Status
}
}
2020-03-07 14:56:42 +05:30
updatedStatus := statusUpdater.UpdateStatus(status)
2020-03-07 14:56:42 +05:30
s.cache.dataMu.Lock()
s.cache.data[statusUpdater.PolicyName()] = updatedStatus
s.cache.dataMu.Unlock()
s.cache.keyToMutex.Get(statusUpdater.PolicyName()).Unlock()
2020-03-07 16:23:17 +05:30
oldStatus, _ := json.Marshal(status)
newStatus, _ := json.Marshal(updatedStatus)
glog.V(4).Infof("\nupdated status of policy - %v\noldStatus:\n%v\nnewStatus:\n%v\n", statusUpdater.PolicyName(), string(oldStatus), string(newStatus))
2020-02-29 17:19:00 +05:30
case <-stopCh:
2020-02-25 20:55:07 +05:30
return
}
}
}
2020-03-07 16:23:17 +05:30
// updatePolicyStatus updates the status in the policy resource definition
//from the status cache, syncing them
2020-02-25 20:55:07 +05:30
func (s *Sync) updatePolicyStatus() {
2020-03-07 14:56:42 +05:30
s.cache.dataMu.Lock()
var nameToStatus = make(map[string]v1.PolicyStatus, len(s.cache.data))
for k, v := range s.cache.data {
2020-02-25 20:55:07 +05:30
nameToStatus[k] = v
}
2020-03-07 14:56:42 +05:30
s.cache.dataMu.Unlock()
2020-02-25 20:55:07 +05:30
for policyName, status := range nameToStatus {
policy, err := s.policyStore.Get(policyName)
2020-02-25 20:55:07 +05:30
if err != nil {
continue
}
policy.Status = status
_, err = s.client.KyvernoV1().ClusterPolicies().UpdateStatus(policy)
if err != nil {
2020-03-07 14:56:42 +05:30
s.cache.dataMu.Lock()
delete(s.cache.data, policyName)
2020-03-07 14:56:42 +05:30
s.cache.dataMu.Unlock()
2020-02-25 20:55:07 +05:30
glog.V(4).Info(err)
}
}
}