2019-11-12 13:32:30 -08:00
package policyviolation
import (
"fmt"
"reflect"
"github.com/golang/glog"
2019-11-13 13:41:08 -08:00
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
2019-11-13 13:56:07 -08:00
kyvernov1 "github.com/nirmata/kyverno/pkg/client/clientset/versioned/typed/kyverno/v1"
2019-11-13 13:41:08 -08:00
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
2019-11-26 18:07:15 -08:00
client "github.com/nirmata/kyverno/pkg/dclient"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2019-11-12 13:32:30 -08:00
)
2019-11-26 18:07:15 -08:00
//NamespacedPV ...
type namespacedPV struct {
// dynamic client
dclient * client . Client
// get/list namespaced policy violation
2019-12-12 16:25:50 -08:00
nspvLister kyvernolister . PolicyViolationLister
2019-11-26 18:07:15 -08:00
// policy violation interface
kyvernoInterface kyvernov1 . KyvernoV1Interface
2019-11-15 12:03:58 -08:00
}
2019-11-26 18:07:15 -08:00
func newNamespacedPV ( dclient * client . Client ,
2019-12-12 16:25:50 -08:00
nspvLister kyvernolister . PolicyViolationLister ,
2019-11-26 18:07:15 -08:00
kyvernoInterface kyvernov1 . KyvernoV1Interface ,
) * namespacedPV {
nspv := namespacedPV {
dclient : dclient ,
nspvLister : nspvLister ,
kyvernoInterface : kyvernoInterface ,
}
return & nspv
2019-11-12 13:32:30 -08:00
}
2019-12-12 16:25:50 -08:00
func ( nspv * namespacedPV ) create ( pv kyverno . PolicyViolationTemplate ) error {
newPv := kyverno . PolicyViolation ( pv )
2019-11-26 18:07:15 -08:00
// PV already exists
oldPv , err := nspv . getExisting ( newPv )
if err != nil {
return err
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
if oldPv == nil {
// create a new policy violation
return nspv . createPV ( & newPv )
2019-11-12 23:19:38 -08:00
}
2019-11-26 18:07:15 -08:00
// policy violation exists
// skip if there is not change, else update the violation
return nspv . updatePV ( & newPv , oldPv )
2019-11-12 13:32:30 -08:00
}
2019-12-12 16:25:50 -08:00
func ( nspv * namespacedPV ) getExisting ( newPv kyverno . PolicyViolation ) ( * kyverno . PolicyViolation , error ) {
2019-12-11 11:15:13 -08:00
var err error
// use labels
policyLabelmap := map [ string ] string { "policy" : newPv . Spec . Policy , "resource" : newPv . Spec . ResourceSpec . ToKey ( ) }
ls , err := converLabelToSelector ( policyLabelmap )
if err != nil {
return nil , err
2019-11-12 14:58:38 -08:00
}
2019-12-12 16:25:50 -08:00
pvs , err := nspv . nspvLister . PolicyViolations ( newPv . GetNamespace ( ) ) . List ( ls )
2019-11-26 18:07:15 -08:00
if err != nil {
glog . Errorf ( "unable to list namespaced policy violations : %v" , err )
return nil , err
2019-11-12 14:58:38 -08:00
}
2019-11-12 20:19:20 -08:00
2019-11-26 18:07:15 -08:00
for _ , pv := range pvs {
// find a policy on same resource and policy combination
if pv . Spec . Policy == newPv . Spec . Policy &&
pv . Spec . ResourceSpec . Kind == newPv . Spec . ResourceSpec . Kind &&
pv . Spec . ResourceSpec . Name == newPv . Spec . ResourceSpec . Name {
return pv , nil
2019-11-12 13:32:30 -08:00
}
}
2019-11-26 18:07:15 -08:00
return nil , nil
2019-11-12 13:32:30 -08:00
}
2019-12-12 16:25:50 -08:00
func ( nspv * namespacedPV ) createPV ( newPv * kyverno . PolicyViolation ) error {
2019-11-26 18:07:15 -08:00
var err error
2019-12-02 17:15:47 -08:00
glog . V ( 4 ) . Infof ( "creating new policy violation for policy %s & resource %s/%s/%s" , newPv . Spec . Policy , newPv . Spec . ResourceSpec . Kind , newPv . Spec . ResourceSpec . Namespace , newPv . Spec . ResourceSpec . Name )
obj , err := retryGetResource ( nspv . dclient , newPv . Spec . ResourceSpec )
2019-11-12 13:32:30 -08:00
if err != nil {
2019-11-26 18:07:15 -08:00
return fmt . Errorf ( "failed to retry getting resource for policy violation %s/%s: %v" , newPv . Name , newPv . Spec . Policy , err )
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
// set owner reference to resource
ownerRef := createOwnerReference ( obj )
newPv . SetOwnerReferences ( [ ] metav1 . OwnerReference { ownerRef } )
2019-11-12 13:32:30 -08:00
2019-11-26 18:07:15 -08:00
// create resource
2019-12-12 16:25:50 -08:00
_ , err = nspv . kyvernoInterface . PolicyViolations ( newPv . GetNamespace ( ) ) . Create ( newPv )
2019-11-26 18:07:15 -08:00
if err != nil {
glog . V ( 4 ) . Infof ( "failed to create Cluster Policy Violation: %v" , err )
return err
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
glog . Infof ( "policy violation created for resource %v" , newPv . Spec . ResourceSpec )
2019-11-12 20:19:20 -08:00
return nil
2019-11-12 13:32:30 -08:00
}
2019-12-12 16:25:50 -08:00
func ( nspv * namespacedPV ) updatePV ( newPv , oldPv * kyverno . PolicyViolation ) error {
2019-11-26 18:07:15 -08:00
var err error
// check if there is any update
if reflect . DeepEqual ( newPv . Spec , oldPv . Spec ) {
glog . V ( 4 ) . Infof ( "policy violation spec %v did not change so not updating it" , newPv . Spec )
return nil
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
// set name
newPv . SetName ( oldPv . Name )
2019-12-11 11:15:13 -08:00
newPv . SetResourceVersion ( oldPv . ResourceVersion )
2019-11-26 18:07:15 -08:00
// update resource
2019-12-12 16:25:50 -08:00
_ , err = nspv . kyvernoInterface . PolicyViolations ( newPv . GetNamespace ( ) ) . Update ( newPv )
2019-11-26 18:07:15 -08:00
if err != nil {
return fmt . Errorf ( "failed to update namespaced polciy violation: %v" , err )
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
glog . Infof ( "namespced policy violation updated for resource %v" , newPv . Spec . ResourceSpec )
return nil
2019-11-12 13:32:30 -08:00
}