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

fix pr comments

This commit is contained in:
Shuting Zhao 2019-08-20 17:01:47 -07:00
parent e83cb51313
commit dcc851dee2
5 changed files with 76 additions and 25 deletions

20
main.go
View file

@ -13,8 +13,9 @@ import (
"github.com/nirmata/kyverno/pkg/namespace" "github.com/nirmata/kyverno/pkg/namespace"
"github.com/nirmata/kyverno/pkg/policy" "github.com/nirmata/kyverno/pkg/policy"
"github.com/nirmata/kyverno/pkg/policyviolation" "github.com/nirmata/kyverno/pkg/policyviolation"
"github.com/nirmata/kyverno/pkg/utils"
"github.com/nirmata/kyverno/pkg/webhooks" "github.com/nirmata/kyverno/pkg/webhooks"
"k8s.io/client-go/informers" kubeinformer "k8s.io/client-go/informers"
"k8s.io/sample-controller/pkg/signals" "k8s.io/sample-controller/pkg/signals"
) )
@ -27,6 +28,7 @@ var (
webhookTimeout int webhookTimeout int
) )
// TODO: tune resync time differently for each informer
const defaultReSyncTime = 10 * time.Second const defaultReSyncTime = 10 * time.Second
func main() { func main() {
@ -48,6 +50,7 @@ func main() {
if err != nil { if err != nil {
glog.Fatalf("Error creating client: %v\n", err) glog.Fatalf("Error creating client: %v\n", err)
} }
// DYNAMIC CLIENT // DYNAMIC CLIENT
// - client for all registered resources // - client for all registered resources
client, err := client.NewClient(clientConfig) client, err := client.NewClient(clientConfig)
@ -65,9 +68,16 @@ func main() {
// - generate event with retry // - generate event with retry
egen := event.NewEventGenerator(client, pInformer.Kyverno().V1alpha1().Policies()) egen := event.NewEventGenerator(client, pInformer.Kyverno().V1alpha1().Policies())
// mutatingWebhookConfiguration Informer kubeClient, err := utils.NewKubeClient(clientConfig)
kubeInformer := informers.NewSharedInformerFactory(client.Kclient, defaultReSyncTime) if err != nil {
mutatingWebhookConfigurationLister := kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations().Lister() glog.Fatalf("Error creating kubernetes client: %v\n", err)
}
// - cache resync time: 10 seconds
kubeInformer := kubeinformer.NewSharedInformerFactoryWithOptions(kubeClient, defaultReSyncTime)
// MutatingWebhookConfiguration Informer
mutatingWebhookConfigurationInformer := kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations()
tlsPair, err := initTLSPemPair(clientConfig, client) tlsPair, err := initTLSPemPair(clientConfig, client)
if err != nil { if err != nil {
@ -91,7 +101,7 @@ func main() {
// - process policy on existing resources // - process policy on existing resources
// - status: violation count // - status: violation count
pc, err := policy.NewPolicyController(pclient, client, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations(), egen, mutatingWebhookConfigurationLister, webhookRegistrationClient) pc, err := policy.NewPolicyController(pclient, client, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations(), egen, mutatingWebhookConfigurationInformer, webhookRegistrationClient)
if err != nil { if err != nil {
glog.Fatalf("error creating policy controller: %v\n", err) glog.Fatalf("error creating policy controller: %v\n", err)
} }

View file

@ -31,7 +31,7 @@ type Client struct {
client dynamic.Interface client dynamic.Interface
cachedClient discovery.CachedDiscoveryInterface cachedClient discovery.CachedDiscoveryInterface
clientConfig *rest.Config clientConfig *rest.Config
Kclient kubernetes.Interface kclient kubernetes.Interface
DiscoveryClient IDiscovery DiscoveryClient IDiscovery
} }
@ -48,7 +48,7 @@ func NewClient(config *rest.Config) (*Client, error) {
client := Client{ client := Client{
client: dclient, client: dclient,
clientConfig: config, clientConfig: config,
Kclient: kclient, kclient: kclient,
} }
// Set discovery client // Set discovery client
// //
@ -75,12 +75,12 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
//TODO: can we use dynamic client to fetch the typed interface //TODO: can we use dynamic client to fetch the typed interface
// or generate a kube client value to access the interface // or generate a kube client value to access the interface
func (c *Client) GetEventsInterface() (event.EventInterface, error) { func (c *Client) GetEventsInterface() (event.EventInterface, error) {
return c.Kclient.CoreV1().Events(""), nil return c.kclient.CoreV1().Events(""), nil
} }
//GetCSRInterface provides type interface for CSR //GetCSRInterface provides type interface for CSR
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) { func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
return c.Kclient.CertificatesV1beta1().CertificateSigningRequests(), nil return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
} }
func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface { func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface {

View file

@ -32,7 +32,7 @@ func NewMockClient(scheme *runtime.Scheme, objects ...runtime.Object) (*Client,
kclient := kubernetesfake.NewSimpleClientset(objects...) kclient := kubernetesfake.NewSimpleClientset(objects...)
return &Client{ return &Client{
client: client, client: client,
Kclient: kclient, kclient: kclient,
}, nil }, nil
} }

View file

@ -27,8 +27,9 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
webhookinformer "k8s.io/client-go/informers/admissionregistration/v1beta1"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
v1beta1 "k8s.io/client-go/listers/admissionregistration/v1beta1" webhooklister "k8s.io/client-go/listers/admissionregistration/v1beta1"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
@ -67,8 +68,8 @@ type PolicyController struct {
pListerSynced cache.InformerSynced pListerSynced cache.InformerSynced
// pvListerSynced returns true if the Policy store has been synced at least once // pvListerSynced returns true if the Policy store has been synced at least once
pvListerSynced cache.InformerSynced pvListerSynced cache.InformerSynced
// mutationwebhookInformer can list/get mutatingwebhookconfigurations // mutationwebhookLister can list/get mutatingwebhookconfigurations
mutationwebhookInformer v1beta1.MutatingWebhookConfigurationLister mutationwebhookLister webhooklister.MutatingWebhookConfigurationLister
// WebhookRegistrationClient // WebhookRegistrationClient
webhookRegistrationClient *webhooks.WebhookRegistrationClient webhookRegistrationClient *webhooks.WebhookRegistrationClient
// Resource manager, manages the mapping for already processed resource // Resource manager, manages the mapping for already processed resource
@ -79,7 +80,7 @@ type PolicyController struct {
// NewPolicyController create a new PolicyController // NewPolicyController create a new PolicyController
func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.Client, pInformer kyvernoinformer.PolicyInformer, pvInformer kyvernoinformer.PolicyViolationInformer, func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.Client, pInformer kyvernoinformer.PolicyInformer, pvInformer kyvernoinformer.PolicyViolationInformer,
eventGen event.Interface, mutationwebhookInformer v1beta1.MutatingWebhookConfigurationLister, webhookRegistrationClient *webhooks.WebhookRegistrationClient) (*PolicyController, error) { eventGen event.Interface, webhookInformer webhookinformer.MutatingWebhookConfigurationInformer, webhookRegistrationClient *webhooks.WebhookRegistrationClient) (*PolicyController, error) {
// Event broad caster // Event broad caster
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartLogging(glog.Infof)
@ -95,7 +96,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.
eventGen: eventGen, eventGen: eventGen,
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "policy_controller"}), eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "policy_controller"}),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"),
mutationwebhookInformer: mutationwebhookInformer,
webhookRegistrationClient: webhookRegistrationClient, webhookRegistrationClient: webhookRegistrationClient,
} }
@ -121,6 +121,8 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.
pc.pListerSynced = pInformer.Informer().HasSynced pc.pListerSynced = pInformer.Informer().HasSynced
pc.pvListerSynced = pInformer.Informer().HasSynced pc.pvListerSynced = pInformer.Informer().HasSynced
pc.mutationwebhookLister = webhookInformer.Lister()
// resource manager // resource manager
// rebuild after 300 seconds/ 5 mins // rebuild after 300 seconds/ 5 mins
//TODO: pass the time in seconds instead of converting it internally //TODO: pass the time in seconds instead of converting it internally
@ -394,7 +396,9 @@ func (pc *PolicyController) syncPolicy(key string) error {
policy, err := pc.pLister.Get(key) policy, err := pc.pLister.Get(key)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
glog.V(2).Infof("Policy %v has been deleted", key) glog.V(2).Infof("Policy %v has been deleted", key)
err = pc.handleWebhookRegistration(true) if err := pc.handleWebhookRegistration(true, nil); err != nil {
glog.Errorln(err)
}
return err return err
} }
@ -402,7 +406,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
return err return err
} }
if err := pc.handleWebhookRegistration(false); err != nil { if err := pc.handleWebhookRegistration(false, policy); err != nil {
glog.Errorln(err) glog.Errorln(err)
} }
@ -421,28 +425,40 @@ func (pc *PolicyController) syncPolicy(key string) error {
return pc.syncStatusOnly(p, pvList) return pc.syncStatusOnly(p, pvList)
} }
func (pc *PolicyController) handleWebhookRegistration(emptyPolicy bool) error { // TODO: here checks mutatingwebhook only
// as 'kubectl scale' is not funtional with validatingwebhook
// refer to https://github.com/nirmata/kyverno/issues/250
func (pc *PolicyController) handleWebhookRegistration(delete bool, policy *kyverno.Policy) error {
policies, _ := pc.pLister.List(labels.NewSelector())
selector := &metav1.LabelSelector{MatchLabels: config.KubePolicyAppLabels} selector := &metav1.LabelSelector{MatchLabels: config.KubePolicyAppLabels}
webhookSelector, err := metav1.LabelSelectorAsSelector(selector) webhookSelector, err := metav1.LabelSelectorAsSelector(selector)
if err != nil { if err != nil {
return fmt.Errorf("invalid label selector: %v", err) return fmt.Errorf("invalid label selector: %v", err)
} }
list, err := pc.mutationwebhookInformer.List(webhookSelector) webhookList, err := pc.mutationwebhookLister.List(webhookSelector)
if err != nil { if err != nil {
return fmt.Errorf("failed to list mutatingwebhookconfigurations, err %v", err) return fmt.Errorf("failed to list mutatingwebhookconfigurations, err %v", err)
} }
if emptyPolicy { if delete {
// deregister webhookconfigurations it it exists if webhookList == nil {
if list != nil { return nil
}
// webhook exist, deregister webhookconfigurations on condition
// check empty policy first, then rule type in terms of O(time)
if policies == nil {
glog.V(3).Infoln("No policy found in the cluster, deregistering webhook") glog.V(3).Infoln("No policy found in the cluster, deregistering webhook")
pc.webhookRegistrationClient.DeregisterMutatingWebhook() pc.webhookRegistrationClient.DeregisterMutatingWebhook()
} else if !webhooks.HasMutateOrValidatePolicies(policies) {
glog.V(3).Infoln("No muatate/validate policy found in the cluster, deregistering webhook")
pc.webhookRegistrationClient.DeregisterMutatingWebhook()
} }
return nil return nil
} }
if list == nil { if webhookList == nil && webhooks.HasMutateOrValidate(*policy) {
glog.V(3).Infoln("Found policy without mutatingwebhook, registering webhook") glog.V(3).Infoln("Found policy without mutatingwebhook, registering webhook")
pc.webhookRegistrationClient.RegisterMutatingWebhook() pc.webhookRegistrationClient.RegisterMutatingWebhook()
} }

View file

@ -1,6 +1,8 @@
package webhooks package webhooks
import ( import (
"reflect"
"github.com/golang/glog" "github.com/golang/glog"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
v1beta1 "k8s.io/api/admission/v1beta1" v1beta1 "k8s.io/api/admission/v1beta1"
@ -26,6 +28,10 @@ func (ws *WebhookServer) manageWebhookConfigurations(policy kyverno.Policy, op v
} }
func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) error { func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) error {
if !HasMutateOrValidate(policy) {
return nil
}
if !ws.webhookRegistrationClient.MutationRegistered.IsSet() { if !ws.webhookRegistrationClient.MutationRegistered.IsSet() {
if err := ws.webhookRegistrationClient.RegisterMutatingWebhook(); err != nil { if err := ws.webhookRegistrationClient.RegisterMutatingWebhook(); err != nil {
return err return err
@ -39,11 +45,30 @@ func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) er
func (ws *WebhookServer) deregisterWebhookConfigurations(policy kyverno.Policy) error { func (ws *WebhookServer) deregisterWebhookConfigurations(policy kyverno.Policy) error {
policies, _ := ws.pLister.List(labels.NewSelector()) policies, _ := ws.pLister.List(labels.NewSelector())
// deregister webhook if no policy found in cluster // deregister webhook if no mutate/validate policy found in cluster
if len(policies) == 1 { if !HasMutateOrValidatePolicies(policies) {
ws.webhookRegistrationClient.DeregisterMutatingWebhook() ws.webhookRegistrationClient.DeregisterMutatingWebhook()
glog.Infoln("Mutating webhook deregistered") glog.Infoln("Mutating webhook deregistered")
} }
return nil return nil
} }
func HasMutateOrValidatePolicies(policies []*kyverno.Policy) bool {
for _, policy := range policies {
if HasMutateOrValidate(*policy) {
return true
}
}
return false
}
func HasMutateOrValidate(policy kyverno.Policy) bool {
for _, rule := range policy.Spec.Rules {
if !reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) || !reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
glog.Infoln(rule.Name)
return true
}
}
return false
}