1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

create namespace pv when validate policy fails

This commit is contained in:
Shuting Zhao 2019-11-12 13:32:30 -08:00
parent e7ec93a5ba
commit 2893cc3f7d
7 changed files with 136 additions and 11 deletions

View file

@ -3,11 +3,10 @@ package main
import (
"flag"
"time"
"github.com/golang/glog"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
clusterpv "github.com/nirmata/kyverno/pkg/clusterpolicyviolation"
"github.com/nirmata/kyverno/pkg/config"
client "github.com/nirmata/kyverno/pkg/dclient"
event "github.com/nirmata/kyverno/pkg/event"
@ -122,7 +121,7 @@ func main() {
// POLICY VIOLATION CONTROLLER
// policy violation cleanup if the corresponding resource is deleted
// status: lastUpdatTime
pvc, err := clusterpv.NewPolicyViolationController(client, pclient, pInformer.Kyverno().V1alpha1().ClusterPolicies(), pInformer.Kyverno().V1alpha1().ClusterPolicyViolations())
pvc, err := policyviolation.NewPolicyViolationController(client, pclient, pInformer.Kyverno().V1alpha1().ClusterPolicies(), pInformer.Kyverno().V1alpha1().ClusterPolicyViolations())
if err != nil {
glog.Fatalf("error creating policy violation controller: %v\n", err)
}
@ -152,7 +151,7 @@ func main() {
// -- annotations on resources with update details on mutation JSON patches
// -- generate policy violation resource
// -- generate events on policy and resource
server, err := webhooks.NewWebhookServer(pclient, client, tlsPair, pInformer.Kyverno().V1alpha1().ClusterPolicies(), pInformer.Kyverno().V1alpha1().ClusterPolicyViolations(), egen, webhookRegistrationClient, pc.GetPolicyStatusAggregator(), configData, policyMetaStore, pvgen, cleanUp)
server, err := webhooks.NewWebhookServer(pclient, client, tlsPair, pInformer.Kyverno().V1alpha1().ClusterPolicies(), pInformer.Kyverno().V1alpha1().ClusterPolicyViolations(), pInformer.Kyverno().V1alpha1().NamespacedPolicyViolations(), egen, webhookRegistrationClient, pc.GetPolicyStatusAggregator(), configData, policyMetaStore, pvgen, cleanUp)
if err != nil {
glog.Fatalf("Unable to create webhook server: %v\n", err)
}

View file

@ -10,7 +10,6 @@ import (
"github.com/nirmata/kyverno/pkg/policyviolation"
)
func (nsc *NamespaceController) report(engineResponses []engine.EngineResponse) {
// generate events
eventInfos := generateEvents(engineResponses)

View file

@ -9,7 +9,7 @@ import (
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1alpha1"
dclient "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/engine"
clusterpv "github.com/nirmata/kyverno/pkg/clusterpolicyviolation"
"github.com/nirmata/kyverno/pkg/policyviolation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)
@ -69,7 +69,7 @@ func getPVonOwnerRef(pvLister kyvernolister.ClusterPolicyViolationLister, dclien
}
// get owners
// getOwners returns nil if there is any error
owners := clusterpv.GetOwners(dclient, *resource)
owners := policyviolation.GetOwners(dclient, *resource)
// as we can have multiple top level owners to a resource
// check if pv exists on each one
// does not check for cycles

View file

@ -1,4 +1,4 @@
package clusterpolicyviolation
package policyviolation
import (
"fmt"
@ -82,7 +82,8 @@ func createClusterPV(pvLister kyvernolister.ClusterPolicyViolationLister, client
// check if there was a previous policy voilation for policy & resource combination
curPv, err := getExistingPolicyViolationIfAny(nil, pvLister, newPv)
if err != nil {
glog.Error(err)
// TODO(shuting): remove
// glog.Error(err)
continue
}
if curPv == nil {
@ -180,7 +181,7 @@ func getExistingPolicyViolationIfAny(pvListerSynced cache.InformerSynced, pvList
}
//TODO: ideally there should be only one policy violation returned
if len(pvs) > 1 {
glog.Errorf("more than one policy violation exists with labels %v", labelMap)
glog.V(4).Infof("more than one policy violation exists with labels %v", labelMap)
return nil, fmt.Errorf("more than one policy violation exists with labels %v", labelMap)
}

View file

@ -1,4 +1,4 @@
package clusterpolicyviolation
package policyviolation
import (
"fmt"

View file

@ -0,0 +1,121 @@
package policyviolation
import (
"fmt"
"reflect"
"github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1alpha1"
engine "github.com/nirmata/kyverno/pkg/engine"
labels "k8s.io/apimachinery/pkg/labels"
)
func CreateNamespacePV(pvLister kyvernolister.NamespacedPolicyViolationLister, client *kyvernoclient.Clientset, engineResponses []engine.EngineResponse) {
var pvs []kyverno.NamespacedPolicyViolation
for _, er := range engineResponses {
// ignore creation of PV for resoruces that are yet to be assigned a name
if er.PolicyResponse.Resource.Name == "" {
glog.V(4).Infof("resource %v, has not been assigned a name, not creating a namespace policy violation for it", er.PolicyResponse.Resource)
continue
}
if !er.IsSuccesful() {
glog.V(4).Infof("Building namespace policy violation for engine response %v", er)
if pv := buildNamespacedPVForPolicy(er); !reflect.DeepEqual(pv, kyverno.NamespacedPolicyViolation{}) {
pvs = append(pvs, pv)
}
}
}
createNamespacedPV(pvLister, client, pvs)
}
func buildNamespacedPVForPolicy(er engine.EngineResponse) kyverno.NamespacedPolicyViolation {
pvResourceSpec := kyverno.ResourceSpec{
Kind: er.PolicyResponse.Resource.Kind,
Namespace: er.PolicyResponse.Resource.Namespace,
Name: er.PolicyResponse.Resource.Name,
}
violatedRules := newViolatedRules(er, "")
return buildNamespacedPolicyViolation(er.PolicyResponse.Policy, pvResourceSpec, violatedRules)
}
//buildNamespacedPolicyViolation returns an value of type PolicyViolation
func buildNamespacedPolicyViolation(policy string, resource kyverno.ResourceSpec, fRules []kyverno.ViolatedRule) kyverno.NamespacedPolicyViolation {
pv := kyverno.NamespacedPolicyViolation{
Spec: kyverno.PolicyViolationSpec{
Policy: policy,
ResourceSpec: resource,
ViolatedRules: fRules,
},
}
//TODO: check if this can be removed or use unstructured?
// pv.SetGroupVersionKind(kyverno.SchemeGroupVersion.WithKind("NamespacedPolicyViolation"))
pv.SetGenerateName("pv-")
return pv
}
func createNamespacedPV(pvLister kyvernolister.NamespacedPolicyViolationLister, client *kyvernoclient.Clientset, pvs []kyverno.NamespacedPolicyViolation) {
if len(pvs) == 0 {
return
}
for _, newPv := range pvs {
glog.V(4).Infof("creating namespaced policyViolation resource for policy %s and resource %s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.ToKey())
// check if there was a previous policy voilation for policy & resource combination
curPv, err := getExistingNamespacedPVIfAny(pvLister, newPv)
if err != nil {
glog.Error(err)
continue
}
if curPv == nil {
glog.V(4).Infof("creating new namespaced policy violation for policy %s & resource %s", newPv.Spec.Policy, newPv.Spec.ResourceSpec.ToKey())
// no existing policy violation, create a new one
_, err := client.KyvernoV1alpha1().NamespacedPolicyViolations(newPv.Spec.ResourceSpec.Namespace).Create(&newPv)
if err != nil {
glog.Error(err)
} else {
glog.Infof("namespaced policy violation created for resource %s", newPv.Spec.ResourceSpec.ToKey())
}
continue
}
// compare the policyviolation spec for existing resource if present else
if reflect.DeepEqual(curPv.Spec, newPv.Spec) {
// if they are equal there has been no change so dont update the polivy violation
glog.V(3).Infof("namespaced policy violation '%s' spec did not change so not updating it", newPv.Spec.ToKey())
glog.V(4).Infof("namespaced policy violation spec %v did not change so not updating it", newPv.Spec)
continue
}
// spec changed so update the policyviolation
glog.V(4).Infof("creating new policy violation for policy %s & resource %s", curPv.Spec.Policy, curPv.Spec.ResourceSpec.ToKey())
//TODO: using a generic name, but would it be helpful to have naming convention for policy violations
// as we can only have one policy violation for each (policy + resource) combination
_, err = client.KyvernoV1alpha1().NamespacedPolicyViolations(newPv.Spec.ResourceSpec.Namespace).Update(&newPv)
if err != nil {
glog.Error(err)
continue
}
glog.Infof("namespaced policy violation updated for resource %s", newPv.Spec.ResourceSpec.ToKey())
}
}
func getExistingNamespacedPVIfAny(nspvLister kyvernolister.NamespacedPolicyViolationLister, newPv kyverno.NamespacedPolicyViolation) (*kyverno.NamespacedPolicyViolation, error) {
// TODO(shuting): list pvs by labels
pvs, err := nspvLister.List(labels.NewSelector())
if err != nil {
return nil, fmt.Errorf("failed to list namespaced policy violations err: %v", err)
}
for _, pv := range pvs {
if pv.Spec.Policy == newPv.Spec.Policy && reflect.DeepEqual(pv.Spec.ResourceSpec, newPv.Spec.ResourceSpec) {
return pv, nil
}
}
return nil, nil
}

View file

@ -36,8 +36,10 @@ type WebhookServer struct {
kyvernoClient *kyvernoclient.Clientset
pLister kyvernolister.ClusterPolicyLister
pvLister kyvernolister.ClusterPolicyViolationLister
namespacepvLister kyvernolister.NamespacedPolicyViolationLister
pListerSynced cache.InformerSynced
pvListerSynced cache.InformerSynced
namespacepvListerSynced cache.InformerSynced
eventGen event.Interface
webhookRegistrationClient *webhookconfig.WebhookRegistrationClient
// API to send policy stats for aggregation
@ -62,6 +64,7 @@ func NewWebhookServer(
tlsPair *tlsutils.TlsPemPair,
pInformer kyvernoinformer.ClusterPolicyInformer,
pvInformer kyvernoinformer.ClusterPolicyViolationInformer,
namespacepvInformer kyvernoinformer.NamespacedPolicyViolationInformer,
eventGen event.Interface,
webhookRegistrationClient *webhookconfig.WebhookRegistrationClient,
policyStatus policy.PolicyStatusInterface,
@ -87,8 +90,10 @@ func NewWebhookServer(
kyvernoClient: kyvernoClient,
pLister: pInformer.Lister(),
pvLister: pvInformer.Lister(),
namespacepvLister: namespacepvInformer.Lister(),
pListerSynced: pvInformer.Informer().HasSynced,
pvListerSynced: pInformer.Informer().HasSynced,
namespacepvListerSynced: namespacepvInformer.Informer().HasSynced,
eventGen: eventGen,
webhookRegistrationClient: webhookRegistrationClient,
policyStatus: policyStatus,