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
labels "k8s.io/apimachinery/pkg/labels"
)
2019-11-26 18:07:15 -08:00
//NamespacedPV ...
type namespacedPV struct {
// dynamic client
dclient * client . Client
// get/list namespaced policy violation
nspvLister kyvernolister . NamespacedPolicyViolationLister
// 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 ,
nspvLister kyvernolister . NamespacedPolicyViolationLister ,
kyvernoInterface kyvernov1 . KyvernoV1Interface ,
) * namespacedPV {
nspv := namespacedPV {
dclient : dclient ,
nspvLister : nspvLister ,
kyvernoInterface : kyvernoInterface ,
}
return & nspv
2019-11-12 13:32:30 -08:00
}
2019-11-26 18:07:15 -08:00
func ( nspv * namespacedPV ) create ( pv kyverno . PolicyViolation ) error {
newPv := kyverno . NamespacedPolicyViolation ( pv )
// 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-11-26 18:07:15 -08:00
func ( nspv * namespacedPV ) getExisting ( newPv kyverno . NamespacedPolicyViolation ) ( * kyverno . NamespacedPolicyViolation , error ) {
pvs , err := nspv . nspvLister . NamespacedPolicyViolations ( newPv . GetNamespace ( ) ) . List ( labels . NewSelector ( ) )
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-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 14:58:38 -08:00
}
2019-11-26 18:07:15 -08:00
return nil , nil
2019-11-12 14:58:38 -08:00
}
2019-11-26 18:07:15 -08:00
func ( nspv * namespacedPV ) createPV ( newPv * kyverno . NamespacedPolicyViolation ) error {
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-26 18:07:15 -08:00
if err != nil {
return fmt . Errorf ( "failed to retry getting resource for policy violation %s/%s: %v" , newPv . Name , newPv . Spec . Policy , err )
}
// set owner reference to resource
ownerRef := createOwnerReference ( obj )
newPv . SetOwnerReferences ( [ ] metav1 . OwnerReference { ownerRef } )
2019-11-13 15:45:36 -08:00
2019-11-26 18:07:15 -08:00
// create resource
_ , err = nspv . kyvernoInterface . NamespacedPolicyViolations ( newPv . GetNamespace ( ) ) . Create ( newPv )
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-11-26 18:07:15 -08:00
func ( nspv * namespacedPV ) updatePV ( newPv , oldPv * kyverno . NamespacedPolicyViolation ) error {
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-11-12 13:32:30 -08:00
2019-11-26 18:07:15 -08:00
// update resource
_ , err = nspv . kyvernoInterface . NamespacedPolicyViolations ( newPv . GetNamespace ( ) ) . Create ( newPv )
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
}