From d593fe1a92217778d6facfbcab9a8b006e7420d8 Mon Sep 17 00:00:00 2001
From: belyshevdenis <belyshev.denis@apriorit.com>
Date: Fri, 1 Mar 2019 14:16:20 +0200
Subject: [PATCH] NK-22: Fixed build error with Selector pointer. Added
 comments. Changed tab to 4 spaces identation. Added unit tests for
 LabelSelector.

---
 controller/controller.go             | 130 ++++++------
 crd/sample-policy.yaml               |   8 +-
 crd/selector-policy.yaml             |   2 +-
 main.go                              |  74 +++----
 pkg/apis/policy/register.go          |   2 +-
 pkg/apis/policy/v1alpha1/register.go |   2 +-
 pkg/apis/policy/v1alpha1/types.go    |  52 ++---
 server/server.go                     | 230 ++++++++++----------
 webhooks/admission.go                | 153 +++++++-------
 webhooks/admission_test.go           | 305 +++++++++++++++++----------
 webhooks/mutation.go                 | 188 +++++++++--------
 webhooks/mutation_test.go            |  58 ++---
 webhooks/utils_test.go               |  36 ++--
 13 files changed, 669 insertions(+), 571 deletions(-)

diff --git a/controller/controller.go b/controller/controller.go
index a4a56c36c0..411ad0f93a 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -1,111 +1,111 @@
 package controller
 
 import (
-	"log"
-	"os"
-	"time"
+    "log"
+    "os"
+    "time"
 
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/client-go/tools/cache"
-	"k8s.io/client-go/tools/clientcmd"
+    "k8s.io/apimachinery/pkg/labels"
+    "k8s.io/client-go/tools/cache"
+    "k8s.io/client-go/tools/clientcmd"
 
-	types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
-	clientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
-	informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
-	lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
+    types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
+    clientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
+    informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
+    lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
 )
 
 // PolicyController for CRD
 type PolicyController struct {
-	policyInformerFactory informers.SharedInformerFactory
-	policyLister          lister.PolicyLister
-	logger                *log.Logger
+    policyInformerFactory informers.SharedInformerFactory
+    policyLister          lister.PolicyLister
+    logger                *log.Logger
 }
 
 // NewPolicyController from cmd args
 func NewPolicyController(masterURL, kubeconfigPath string, logger *log.Logger) (*PolicyController, error) {
-	if logger == nil {
-		logger = log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile)
-	}
+    if logger == nil {
+        logger = log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile)
+    }
 
-	cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfigPath)
-	if err != nil {
-		logger.Printf("Error building kubeconfig: %v\n", err)
-		return nil, err
-	}
+    cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfigPath)
+    if err != nil {
+        logger.Printf("Error building kubeconfig: %v\n", err)
+        return nil, err
+    }
 
-	policyClientset, err := clientset.NewForConfig(cfg)
-	if err != nil {
-		logger.Printf("Error building policy clientset: %v\n", err)
-		return nil, err
-	}
+    policyClientset, err := clientset.NewForConfig(cfg)
+    if err != nil {
+        logger.Printf("Error building policy clientset: %v\n", err)
+        return nil, err
+    }
 
-	policyInformerFactory := informers.NewSharedInformerFactory(policyClientset, time.Second*30)
-	policyInformer := policyInformerFactory.Nirmata().V1alpha1().Policies()
+    policyInformerFactory := informers.NewSharedInformerFactory(policyClientset, time.Second*30)
+    policyInformer := policyInformerFactory.Nirmata().V1alpha1().Policies()
 
-	controller := &PolicyController{
-		policyInformerFactory: policyInformerFactory,
-		policyLister:          policyInformer.Lister(),
-		logger:                logger,
-	}
+    controller := &PolicyController{
+        policyInformerFactory: policyInformerFactory,
+        policyLister:          policyInformer.Lister(),
+        logger:                logger,
+    }
 
-	policyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
-		AddFunc:    controller.createPolicyHandler,
-		UpdateFunc: controller.updatePolicyHandler,
-		DeleteFunc: controller.deletePolicyHandler,
-	})
+    policyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
+        AddFunc:    controller.createPolicyHandler,
+        UpdateFunc: controller.updatePolicyHandler,
+        DeleteFunc: controller.deletePolicyHandler,
+    })
 
-	return controller, nil
+    return controller, nil
 }
 
 // Run is main controller thread
 func (c *PolicyController) Run(stopCh <-chan struct{}) {
-	c.policyInformerFactory.Start(stopCh)
+    c.policyInformerFactory.Start(stopCh)
 }
 
 // GetPolicies retrieves all policy resources
 // from cache. Cache is refreshed by informer
 func (c *PolicyController) GetPolicies() []types.Policy {
-	// Create nil Selector to grab all the policies
-	selector := labels.NewSelector()
-	cachedPolicies, err := c.policyLister.List(selector)
+    // Create nil Selector to grab all the policies
+    selector := labels.NewSelector()
+    cachedPolicies, err := c.policyLister.List(selector)
 
-	if err != nil {
-		c.logger.Printf("Error: %v", err)
-		return nil
-	}
+    if err != nil {
+        c.logger.Printf("Error: %v", err)
+        return nil
+    }
 
-	var policies []types.Policy
-	for _, elem := range cachedPolicies {
-		policies = append(policies, *elem.DeepCopy())
-	}
+    var policies []types.Policy
+    for _, elem := range cachedPolicies {
+        policies = append(policies, *elem.DeepCopy())
+    }
 
-	return policies
+    return policies
 }
 
 func (c *PolicyController) createPolicyHandler(resource interface{}) {
-	key := c.getResourceKey(resource)
-	c.logger.Printf("Created policy: %s\n", key)
+    key := c.getResourceKey(resource)
+    c.logger.Printf("Created policy: %s\n", key)
 }
 
 func (c *PolicyController) updatePolicyHandler(oldResource, newResource interface{}) {
-	oldKey := c.getResourceKey(oldResource)
-	newKey := c.getResourceKey(newResource)
+    oldKey := c.getResourceKey(oldResource)
+    newKey := c.getResourceKey(newResource)
 
-	c.logger.Printf("Updated policy from %s to %s\n", oldKey, newKey)
+    c.logger.Printf("Updated policy from %s to %s\n", oldKey, newKey)
 }
 
 func (c *PolicyController) deletePolicyHandler(resource interface{}) {
-	key := c.getResourceKey(resource)
-	c.logger.Printf("Deleted policy: %s\n", key)
+    key := c.getResourceKey(resource)
+    c.logger.Printf("Deleted policy: %s\n", key)
 }
 
 func (c *PolicyController) getResourceKey(resource interface{}) string {
-	if key, err := cache.MetaNamespaceKeyFunc(resource); err != nil {
-		c.logger.Fatalf("Error retrieving policy key: %v\n", err)
-	} else {
-		return key
-	}
+    if key, err := cache.MetaNamespaceKeyFunc(resource); err != nil {
+        c.logger.Fatalf("Error retrieving policy key: %v\n", err)
+    } else {
+        return key
+    }
 
-	return ""
+    return ""
 }
diff --git a/crd/sample-policy.yaml b/crd/sample-policy.yaml
index 15fc65fee5..8a9de6aecd 100644
--- a/crd/sample-policy.yaml
+++ b/crd/sample-policy.yaml
@@ -1,7 +1,7 @@
-apiVersion: nirmata.io/v1alpha1
+apiVersion: policy.nirmata.io/v1alpha1
 kind: Policy
 metadata:
-    name: hello-policy
+  name: hello-policy
 spec:
-    policySpec: 'hi'
-    image: hello-policy-image
+  policySpec: 'hi'
+  image: hello-policy-image
diff --git a/crd/selector-policy.yaml b/crd/selector-policy.yaml
index 9fdd2df055..8269eb55fe 100644
--- a/crd/selector-policy.yaml
+++ b/crd/selector-policy.yaml
@@ -1,4 +1,4 @@
-apiVersion: nirmata.io/v1alpha1
+apiVersion: policy.nirmata.io/v1alpha1
 kind : Policy
 metadata:
   name: selector-policy
diff --git a/main.go b/main.go
index ee8437553c..82450b1f27 100644
--- a/main.go
+++ b/main.go
@@ -1,58 +1,58 @@
 package main
 
 import (
-	"flag"
-	"fmt"
-	"log"
-	"os"
+    "flag"
+    "fmt"
+    "log"
+    "os"
 
-	"github.com/nirmata/kube-policy/controller"
-	"github.com/nirmata/kube-policy/server"
+    "github.com/nirmata/kube-policy/controller"
+    "github.com/nirmata/kube-policy/server"
 
-	"k8s.io/sample-controller/pkg/signals"
+    "k8s.io/sample-controller/pkg/signals"
 )
 
 var (
-	masterURL  string
-	kubeconfig string
-	cert       string
-	key        string
+    masterURL  string
+    kubeconfig string
+    cert       string
+    key        string
 )
 
 func main() {
-	flag.Parse()
+    flag.Parse()
 
-	if cert == "" || key == "" {
-		log.Fatal("TLS certificate or/and key is not set")
-	}
+    if cert == "" || key == "" {
+        log.Fatal("TLS certificate or/and key is not set")
+    }
 
-	crdcLogger := log.New(os.Stdout, "Policy Controller: ", log.LstdFlags|log.Lshortfile)
-	controller, err := controller.NewPolicyController(masterURL, kubeconfig, crdcLogger)
-	if err != nil {
-		fmt.Printf("Error creating PolicyController! Error: %s\n", err)
-		return
-	}
+    crdcLogger := log.New(os.Stdout, "Policy Controller: ", log.LstdFlags|log.Lshortfile)
+    controller, err := controller.NewPolicyController(masterURL, kubeconfig, crdcLogger)
+    if err != nil {
+        fmt.Printf("Error creating PolicyController! Error: %s\n", err)
+        return
+    }
 
-	httpLogger := log.New(os.Stdout, "HTTPS Server: ", log.LstdFlags|log.Lshortfile)
-	server := server.NewWebhookServer(cert, key, controller, httpLogger)
-	server.RunAsync()
+    httpLogger := log.New(os.Stdout, "HTTPS Server: ", log.LstdFlags|log.Lshortfile)
+    server := server.NewWebhookServer(cert, key, controller, httpLogger)
+    server.RunAsync()
 
-	stopCh := signals.SetupSignalHandler()
-	controller.Run(stopCh)
+    stopCh := signals.SetupSignalHandler()
+    controller.Run(stopCh)
 
-	if err != nil {
-		fmt.Printf("Error running PolicyController! Error: %s\n", err)
-	}
+    if err != nil {
+        fmt.Printf("Error running PolicyController! Error: %s\n", err)
+    }
 
-	fmt.Println("Policy Controller has started")
-	<-stopCh
-	server.Stop()
-	fmt.Println("Policy Controller has stopped")
+    fmt.Println("Policy Controller has started")
+    <-stopCh
+    server.Stop()
+    fmt.Println("Policy Controller has stopped")
 }
 
 func init() {
-	flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
-	flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
-	flag.StringVar(&cert, "cert", "", "TLS certificate used in connection with cluster.")
-	flag.StringVar(&key, "key", "", "Key, used in TLS connection.")
+    flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
+    flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
+    flag.StringVar(&cert, "cert", "", "TLS certificate used in connection with cluster.")
+    flag.StringVar(&key, "key", "", "Key, used in TLS connection.")
 }
diff --git a/pkg/apis/policy/register.go b/pkg/apis/policy/register.go
index a3301eb74f..9e9831538d 100644
--- a/pkg/apis/policy/register.go
+++ b/pkg/apis/policy/register.go
@@ -1,5 +1,5 @@
 package policy
 
 const (
-	GroupName = "policy.nirmata.io"
+    GroupName = "policy.nirmata.io"
 )
diff --git a/pkg/apis/policy/v1alpha1/register.go b/pkg/apis/policy/v1alpha1/register.go
index dd21eacbfc..cd8c355461 100644
--- a/pkg/apis/policy/v1alpha1/register.go
+++ b/pkg/apis/policy/v1alpha1/register.go
@@ -4,7 +4,7 @@ import (
     metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     "k8s.io/apimachinery/pkg/runtime"
     "k8s.io/apimachinery/pkg/runtime/schema"
-         
+
     "github.com/nirmata/kube-policy/pkg/apis/policy"
 )
 
diff --git a/pkg/apis/policy/v1alpha1/types.go b/pkg/apis/policy/v1alpha1/types.go
index 36e18b0275..f3cfccf29b 100644
--- a/pkg/apis/policy/v1alpha1/types.go
+++ b/pkg/apis/policy/v1alpha1/types.go
@@ -1,7 +1,7 @@
 package v1alpha1
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 // +genclient
@@ -9,63 +9,63 @@ import (
 
 // Policy is a specification for a Policy resource
 type Policy struct {
-	metav1.TypeMeta   `json:",inline"`
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-	Spec              PolicySpec   `json:"spec"`
-	Status            PolicyStatus `json:"status"`
+    metav1.TypeMeta   `json:",inline"`
+    metav1.ObjectMeta `json:"metadata,omitempty"`
+    Spec              PolicySpec   `json:"spec"`
+    Status            PolicyStatus `json:"status"`
 }
 
 // PolicySpec is the spec for a Policy resource
 type PolicySpec struct {
-	FailurePolicy *string      `json:"failurePolicy"`
-	Rules         []PolicyRule `json:"rules"`
+    FailurePolicy *string      `json:"failurePolicy"`
+    Rules         []PolicyRule `json:"rules"`
 }
 
 // PolicyRule is policy rule that will be applied to resource
 type PolicyRule struct {
-	Resource           PolicyResource         `json:"resource"`
-	Patches            []PolicyPatch          `json:"patch,omitempty"`
-	ConfigMapGenerator *PolicyConfigGenerator `json:"configMapGenerator,omitempty"`
-	SecretGenerator    *PolicyConfigGenerator `json:"secretGenerator,omitempty"`
+    Resource           PolicyResource         `json:"resource"`
+    Patches            []PolicyPatch          `json:"patch,omitempty"`
+    ConfigMapGenerator *PolicyConfigGenerator `json:"configMapGenerator,omitempty"`
+    SecretGenerator    *PolicyConfigGenerator `json:"secretGenerator,omitempty"`
 }
 
 // PolicyResource describes the resource rule applied to
 type PolicyResource struct {
-	Kind     string               `json:"kind"`
-	Name     *string              `json:"name"`
-	Selector metav1.LabelSelector `json:"selector,omitempty"`
+    Kind     string                `json:"kind"`
+    Name     *string               `json:"name"`
+    Selector *metav1.LabelSelector `json:"selector,omitempty"`
 }
 
 // PolicyPatch is TODO
 type PolicyPatch struct {
-	Path      string `json:"path"`
-	Operation string `json:"op"`
-	Value     string `json:"value"`
+    Path      string `json:"path"`
+    Operation string `json:"op"`
+    Value     string `json:"value"`
 }
 
 // PolicyConfigGenerator is TODO
 type PolicyConfigGenerator struct {
-	Name     string            `json:"name"`
-	CopyFrom *PolicyCopyFrom   `json:"copyFrom"`
-	Data     map[string]string `json:"data"`
+    Name     string            `json:"name"`
+    CopyFrom *PolicyCopyFrom   `json:"copyFrom"`
+    Data     map[string]string `json:"data"`
 }
 
 // PolicyCopyFrom is TODO
 type PolicyCopyFrom struct {
-	Namespace string `json:"namespace"`
-	Name      string `json:"name"`
+    Namespace string `json:"namespace"`
+    Name      string `json:"name"`
 }
 
 // PolicyStatus is the status for a Policy resource
 type PolicyStatus struct {
-	Logs []string `json:"log"`
+    Logs []string `json:"log"`
 }
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // PolicyList is a list of Policy resources
 type PolicyList struct {
-	metav1.TypeMeta `json:",inline"`
-	metav1.ListMeta `json:"metadata"`
-	Items           []Policy `json:"items"`
+    metav1.TypeMeta `json:",inline"`
+    metav1.ListMeta `json:"metadata"`
+    Items           []Policy `json:"items"`
 }
diff --git a/server/server.go b/server/server.go
index 3eb371994c..cb814c0c5e 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1,158 +1,158 @@
 package server
 
 import (
-	"context"
-	"crypto/tls"
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"os"
-	"time"
+    "context"
+    "crypto/tls"
+    "encoding/json"
+    "fmt"
+    "io/ioutil"
+    "log"
+    "net/http"
+    "os"
+    "time"
 
-	controller "github.com/nirmata/kube-policy/controller"
-	webhooks "github.com/nirmata/kube-policy/webhooks"
-	v1beta1 "k8s.io/api/admission/v1beta1"
+    controller "github.com/nirmata/kube-policy/controller"
+    webhooks "github.com/nirmata/kube-policy/webhooks"
+    v1beta1 "k8s.io/api/admission/v1beta1"
 )
 
 // WebhookServer is a struct that describes
 // TLS server with mutation webhook
 type WebhookServer struct {
-	server           http.Server
-	logger           *log.Logger
-	policyController *controller.PolicyController
-	mutationWebhook  *webhooks.MutationWebhook
+    server           http.Server
+    logger           *log.Logger
+    policyController *controller.PolicyController
+    mutationWebhook  *webhooks.MutationWebhook
 }
 
 // NewWebhookServer creates new instance of WebhookServer and configures it
 func NewWebhookServer(certFile string, keyFile string, controller *controller.PolicyController, logger *log.Logger) *WebhookServer {
-	if logger == nil {
-		logger = log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile)
-	}
-	if controller == nil {
-		logger.Fatal("Controller is not specified for webhook server")
-	}
+    if logger == nil {
+        logger = log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile)
+    }
+    if controller == nil {
+        logger.Fatal("Controller is not specified for webhook server")
+    }
 
-	var config tls.Config
-	pair, err := tls.LoadX509KeyPair(certFile, keyFile)
-	if err != nil {
-		logger.Fatal("Unable to load certificate and key: ", err)
-	}
-	config.Certificates = []tls.Certificate{pair}
+    var config tls.Config
+    pair, err := tls.LoadX509KeyPair(certFile, keyFile)
+    if err != nil {
+        logger.Fatal("Unable to load certificate and key: ", err)
+    }
+    config.Certificates = []tls.Certificate{pair}
 
-	mw, err := webhooks.NewMutationWebhook(logger)
-	if err != nil {
-		logger.Fatal("Unable to create mutation webhook: ", err)
-	}
+    mw, err := webhooks.NewMutationWebhook(logger)
+    if err != nil {
+        logger.Fatal("Unable to create mutation webhook: ", err)
+    }
 
-	ws := &WebhookServer{
-		logger:           logger,
-		policyController: controller,
-		mutationWebhook:  mw,
-	}
+    ws := &WebhookServer{
+        logger:           logger,
+        policyController: controller,
+        mutationWebhook:  mw,
+    }
 
-	mux := http.NewServeMux()
-	mux.HandleFunc("/mutate", ws.serve)
+    mux := http.NewServeMux()
+    mux.HandleFunc("/mutate", ws.serve)
 
-	ws.server = http.Server{
-		Addr:         ":443", // Listen on port for HTTPS requests
-		TLSConfig:    &config,
-		Handler:      mux,
-		ErrorLog:     logger,
-		ReadTimeout:  15 * time.Second,
-		WriteTimeout: 15 * time.Second,
-	}
+    ws.server = http.Server{
+        Addr:         ":443", // Listen on port for HTTPS requests
+        TLSConfig:    &config,
+        Handler:      mux,
+        ErrorLog:     logger,
+        ReadTimeout:  15 * time.Second,
+        WriteTimeout: 15 * time.Second,
+    }
 
-	return ws
+    return ws
 }
 
 func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
-	if r.URL.Path == "/mutate" {
-		admissionReview := ws.parseAdmissionReview(r, w)
-		if admissionReview == nil {
-			return
-		}
+    if r.URL.Path == "/mutate" {
+        admissionReview := ws.parseAdmissionReview(r, w)
+        if admissionReview == nil {
+            return
+        }
 
-		var admissionResponse *v1beta1.AdmissionResponse
-		if webhooks.AdmissionIsRequired(admissionReview.Request) {
-			admissionResponse = ws.mutationWebhook.Mutate(admissionReview.Request, ws.policyController.GetPolicies())
-		}
+        var admissionResponse *v1beta1.AdmissionResponse
+        if webhooks.AdmissionIsRequired(admissionReview.Request) {
+            admissionResponse = ws.mutationWebhook.Mutate(admissionReview.Request, ws.policyController.GetPolicies())
+        }
 
-		if admissionResponse == nil {
-			admissionResponse = &v1beta1.AdmissionResponse{
-				Allowed: true,
-			}
-		}
+        if admissionResponse == nil {
+            admissionResponse = &v1beta1.AdmissionResponse{
+                Allowed: true,
+            }
+        }
 
-		admissionReview.Response = admissionResponse
-		admissionReview.Response.UID = admissionReview.Request.UID
+        admissionReview.Response = admissionResponse
+        admissionReview.Response.UID = admissionReview.Request.UID
 
-		responseJson, err := json.Marshal(admissionReview)
-		if err != nil {
-			http.Error(w, fmt.Sprintf("Could not encode response: %v", err), http.StatusInternalServerError)
-			return
-		}
+        responseJson, err := json.Marshal(admissionReview)
+        if err != nil {
+            http.Error(w, fmt.Sprintf("Could not encode response: %v", err), http.StatusInternalServerError)
+            return
+        }
 
-		ws.logger.Printf("Response body\n:%v", string(responseJson))
-		w.Header().Set("Content-Type", "application/json; charset=utf-8")
-		if _, err := w.Write(responseJson); err != nil {
-			http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
-		}
-	} else {
-		http.Error(w, fmt.Sprintf("Unexpected method path: %v", r.URL.Path), http.StatusNotFound)
-	}
+        ws.logger.Printf("Response body\n:%v", string(responseJson))
+        w.Header().Set("Content-Type", "application/json; charset=utf-8")
+        if _, err := w.Write(responseJson); err != nil {
+            http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
+        }
+    } else {
+        http.Error(w, fmt.Sprintf("Unexpected method path: %v", r.URL.Path), http.StatusNotFound)
+    }
 }
 
 // Answers to the http.ResponseWriter if request is not valid
 func (ws *WebhookServer) parseAdmissionReview(request *http.Request, writer http.ResponseWriter) *v1beta1.AdmissionReview {
-	var body []byte
-	if request.Body != nil {
-		if data, err := ioutil.ReadAll(request.Body); err == nil {
-			body = data
-		}
-	}
-	if len(body) == 0 {
-		ws.logger.Print("Error: empty body")
-		http.Error(writer, "empty body", http.StatusBadRequest)
-		return nil
-	}
+    var body []byte
+    if request.Body != nil {
+        if data, err := ioutil.ReadAll(request.Body); err == nil {
+            body = data
+        }
+    }
+    if len(body) == 0 {
+        ws.logger.Print("Error: empty body")
+        http.Error(writer, "empty body", http.StatusBadRequest)
+        return nil
+    }
 
-	contentType := request.Header.Get("Content-Type")
-	if contentType != "application/json" {
-		ws.logger.Printf("Error: invalid Content-Type: %v", contentType)
-		http.Error(writer, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
-		return nil
-	}
+    contentType := request.Header.Get("Content-Type")
+    if contentType != "application/json" {
+        ws.logger.Printf("Error: invalid Content-Type: %v", contentType)
+        http.Error(writer, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
+        return nil
+    }
 
-	admissionReview := &v1beta1.AdmissionReview{}
-	if err := json.Unmarshal(body, &admissionReview); err != nil {
-		ws.logger.Printf("Error: Can't decode body as AdmissionReview: %v", err)
-		http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
-		return nil
-	} else {
-		ws.logger.Printf("Request body:\n%v", string(body))
-		return admissionReview
-	}
+    admissionReview := &v1beta1.AdmissionReview{}
+    if err := json.Unmarshal(body, &admissionReview); err != nil {
+        ws.logger.Printf("Error: Can't decode body as AdmissionReview: %v", err)
+        http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
+        return nil
+    } else {
+        ws.logger.Printf("Request body:\n%v", string(body))
+        return admissionReview
+    }
 }
 
 // RunAsync runs TLS server in separate
 // thread and returns control immediately
 func (ws *WebhookServer) RunAsync() {
-	go func(ws *WebhookServer) {
-		err := ws.server.ListenAndServeTLS("", "")
-		if err != nil {
-			ws.logger.Fatal(err)
-		}
-	}(ws)
+    go func(ws *WebhookServer) {
+        err := ws.server.ListenAndServeTLS("", "")
+        if err != nil {
+            ws.logger.Fatal(err)
+        }
+    }(ws)
 }
 
 // Stop stops TLS server
 func (ws *WebhookServer) Stop() {
-	err := ws.server.Shutdown(context.Background())
-	if err != nil {
-		// Error from closing listeners, or context timeout:
-		ws.logger.Printf("Server Shutdown error: %v", err)
-		ws.server.Close()
-	}
+    err := ws.server.Shutdown(context.Background())
+    if err != nil {
+        // Error from closing listeners, or context timeout:
+        ws.logger.Printf("Server Shutdown error: %v", err)
+        ws.server.Close()
+    }
 }
diff --git a/webhooks/admission.go b/webhooks/admission.go
index 262cb9de6b..ff1f36138e 100644
--- a/webhooks/admission.go
+++ b/webhooks/admission.go
@@ -1,109 +1,110 @@
 package webhooks
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
-	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/api/admission/v1beta1"
-	"encoding/json"
+    "encoding/json"
+
+    types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
+    "k8s.io/api/admission/v1beta1"
+    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    "k8s.io/apimachinery/pkg/labels"
 )
 
 var supportedKinds = [...]string{
-	"ConfigMap",
-	"CronJob",
-	"DaemonSet",
-	"Deployment",
-	"Endpoint",
-	"HorizontalPodAutoscaler",
-	"Ingress",
-	"Job",
-	"LimitRange",
-	"Namespace",
-	"NetworkPolicy",
-	"PersistentVolumeClaim",
-	"PodDisruptionBudget",
-	"PodTemplate",
-	"ResourceQuota",
-	"Secret",
-	"Service",
-	"StatefulSet",
+    "ConfigMap",
+    "CronJob",
+    "DaemonSet",
+    "Deployment",
+    "Endpoint",
+    "HorizontalPodAutoscaler",
+    "Ingress",
+    "Job",
+    "LimitRange",
+    "Namespace",
+    "NetworkPolicy",
+    "PersistentVolumeClaim",
+    "PodDisruptionBudget",
+    "PodTemplate",
+    "ResourceQuota",
+    "Secret",
+    "Service",
+    "StatefulSet",
 }
 
 func kindIsSupported(kind string) bool {
-	for _, k := range supportedKinds {
-		if k == kind {
-			return true
-		}
-	}
-	return false
+    for _, k := range supportedKinds {
+        if k == kind {
+            return true
+        }
+    }
+    return false
 }
 
 // AdmissionIsRequired checks for admission if kind is supported
 func AdmissionIsRequired(request *v1beta1.AdmissionRequest) bool {
-	// Here you can make additional hardcoded checks
-	return kindIsSupported(request.Kind.Kind)
+    // Here you can make additional hardcoded checks
+    return kindIsSupported(request.Kind.Kind)
 }
 
 // IsRuleApplicableToRequest checks requests kind, name and labels to fit the policy
 func IsRuleApplicableToRequest(policyResource types.PolicyResource, request *v1beta1.AdmissionRequest) bool {
-	if policyResource.Selector == nil && policyResource.Name == nil {
-		// TODO: selector or name MUST be specified
-		return false
-	}
-	
-	if policyResource.Kind != request.Kind.Kind {
-		return false
-	}
+    if policyResource.Selector == nil && policyResource.Name == nil {
+        // TODO: selector or name MUST be specified
+        return false
+    }
+
+    if policyResource.Kind != request.Kind.Kind {
+        return false
+    }
 
     if request.Object.Raw != nil {
-		meta := parseMetadataFromObject(request.Object.Raw)
-		name := parseNameFromMetadata(meta)
+        meta := parseMetadataFromObject(request.Object.Raw)
+        name := parseNameFromMetadata(meta)
 
-		if (policyResource.Name != nil && *policyResource.Name != name) {
-			return false
-		}
-		
-		if policyResource.Selector != nil {
-			selector, err := metav1.LabelSelectorAsSelector(policyResource.Selector)
+        if policyResource.Name != nil && *policyResource.Name != name {
+            return false
+        }
 
-			if err != nil {
-				// TODO: log that selector is invalid
-				return false
-			}
-			
-			labelMap := parseLabelsFromMetadata(meta)
-			
-			if !selector.Matches(labelMap) {
-				return false
-			}
-		}
-	}
+        if policyResource.Selector != nil {
+            selector, err := metav1.LabelSelectorAsSelector(policyResource.Selector)
 
-	return true
+            if err != nil {
+                // TODO: log that selector is invalid
+                return false
+            }
+
+            labelMap := parseLabelsFromMetadata(meta)
+
+            if !selector.Matches(labelMap) {
+                return false
+            }
+        }
+    }
+
+    return true
 }
 
 func parseMetadataFromObject(bytes []byte) map[string]interface{} {
-	var objectJSON map[string]interface{}
-	json.Unmarshal(bytes, &objectJSON)
-	
-	return objectJSON["metadata"].(map[string]interface{})
+    var objectJSON map[string]interface{}
+    json.Unmarshal(bytes, &objectJSON)
+
+    return objectJSON["metadata"].(map[string]interface{})
 }
 
 func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
-	if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
-		labelMap := make(labels.Set, len(interfaceMap))
+    if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
+        labelMap := make(labels.Set, len(interfaceMap))
 
-		for key, value := range interfaceMap {
-			labelMap[key] = value.(string)
-		}
-		return labelMap
-	}
-	return nil
+        for key, value := range interfaceMap {
+            labelMap[key] = value.(string)
+        }
+        return labelMap
+    }
+    return nil
 }
 
 func parseNameFromMetadata(meta map[string]interface{}) string {
     if name, ok := meta["name"].(string); ok {
-		return name
-	}
-	return ""
-}
\ No newline at end of file
+        return name
+    }
+    return ""
+}
diff --git a/webhooks/admission_test.go b/webhooks/admission_test.go
index 226083297f..3bccc69f56 100644
--- a/webhooks/admission_test.go
+++ b/webhooks/admission_test.go
@@ -1,133 +1,224 @@
 package webhooks_test
 
 import (
-	"testing"
+    "testing"
 
-	types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
-	"github.com/nirmata/kube-policy/webhooks"
-	v1beta1 "k8s.io/api/admission/v1beta1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
+    "github.com/nirmata/kube-policy/webhooks"
+    v1beta1 "k8s.io/api/admission/v1beta1"
+    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 func TestAdmissionIsRequired(t *testing.T) {
-	var request v1beta1.AdmissionRequest
-	request.Kind.Kind = "ConfigMap"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "CronJob"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "DaemonSet"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Deployment"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Endpoint"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "HorizontalPodAutoscaler"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Ingress"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Job"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "LimitRange"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Namespace"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "NetworkPolicy"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "PersistentVolumeClaim"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "PodDisruptionBudget"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "PodTemplate"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "ResourceQuota"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Secret"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "Service"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
-	request.Kind.Kind = "StatefulSet"
-	assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    var request v1beta1.AdmissionRequest
+    request.Kind.Kind = "ConfigMap"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "CronJob"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "DaemonSet"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Deployment"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Endpoint"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "HorizontalPodAutoscaler"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Ingress"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Job"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "LimitRange"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Namespace"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "NetworkPolicy"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "PersistentVolumeClaim"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "PodDisruptionBudget"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "PodTemplate"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "ResourceQuota"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Secret"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "Service"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
+    request.Kind.Kind = "StatefulSet"
+    assertEq(t, true, webhooks.AdmissionIsRequired(&request))
 }
 
 func TestIsRuleResourceFitsRequest_Kind(t *testing.T) {
-	resourceName := "test-config-map"
-	resource := types.PolicyResource {
-		Kind: "ConfigMap",
-		Name: &resourceName,
-	}
-	request := v1beta1.AdmissionRequest {
-		Kind: metav1.GroupVersionKind{ Kind: "ConfigMap" },
-	}
+    resourceName := "test-config-map"
+    resource := types.PolicyResource{
+        Kind: "ConfigMap",
+        Name: &resourceName,
+    }
+    request := v1beta1.AdmissionRequest{
+        Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
+    }
 
-	objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
+    objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
 
-	assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
-	resource.Kind = "Deployment"
-	assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+    resource.Kind = "Deployment"
+    assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
 }
 
 func TestIsRuleResourceFitsRequest_Name(t *testing.T) {
-	resourceName := "test-config-map"
-	resource := types.PolicyResource {
-		Kind: "ConfigMap",
-		Name: &resourceName,
-	}
-	request := v1beta1.AdmissionRequest{
-		Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
-	}
+    resourceName := "test-config-map"
+    resource := types.PolicyResource{
+        Kind: "ConfigMap",
+        Name: &resourceName,
+    }
+    request := v1beta1.AdmissionRequest{
+        Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
+    }
 
-	objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
-	assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
-	resourceName = "test-config-map-new"
-	assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
+    objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+    resourceName = "test-config-map-new"
+    assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
 
-	objectByteArray = []byte(`{"metadata":{"name":"test-config-map-new","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
-	assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+    objectByteArray = []byte(`{"metadata":{"name":"test-config-map-new","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
 
-	objectByteArray = []byte(`{"metadata":{"name":"","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
-	assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
+    objectByteArray = []byte(`{"metadata":{"name":"","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+    assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
 }
 
-func TestIsRuleResourceFitsRequest_Selector(t *testing.T) {
-	resource := types.PolicyResource {
-		Kind: "ConfigMap",
-		Selector: &metav1.LabelSelector {
-            MatchLabels: map[string]string {
-				"label1" : "test1",
-				"label2" : "test2",
-			},
-			MatchExpressions: nil,
-		},
-	}
+func TestIsRuleResourceFitsRequest_MatchExpressions(t *testing.T) {
+    request := v1beta1.AdmissionRequest{
+        Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
+    }
 
-	request := v1beta1.AdmissionRequest{
-		Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
-	}
+    resource := types.PolicyResource{
+        Kind: "ConfigMap",
+        Selector: &metav1.LabelSelector{
+            MatchLabels: nil,
+            MatchExpressions: []metav1.LabelSelectorRequirement{
+                metav1.LabelSelectorRequirement{
+                    Key:      "label2",
+                    Operator: "NotIn",
+                    Values: []string{
+                        "sometest1",
+                    },
+                },
+                metav1.LabelSelectorRequirement{
+                    Key:      "label1",
+                    Operator: "In",
+                    Values: []string{
+                        "test1",
+                        "test8",
+                        "test201",
+                    },
+                },
+                metav1.LabelSelectorRequirement{
+                    Key:      "label3",
+                    Operator: "DoesNotExist",
+                    Values:   nil,
+                },
+            },
+        },
+    }
 
-	objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
-	assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+    objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
 
-	objectByteArray = []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label3":"test1","label2":"test2"}}}`)
-	request.Object.Raw = objectByteArray
-	assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+}
 
-	resource = types.PolicyResource {
-		Kind: "ConfigMap",
-		Selector: &metav1.LabelSelector {
-            MatchLabels: map[string]string {
-				"label3" : "test1",
-				"label2" : "test2",
-			},
-			MatchExpressions: nil,
-		},
-	}
+func TestIsRuleResourceFitsRequest_MatchLabels(t *testing.T) {
+    resource := types.PolicyResource{
+        Kind: "ConfigMap",
+        Selector: &metav1.LabelSelector{
+            MatchLabels: map[string]string{
+                "label1": "test1",
+                "label2": "test2",
+            },
+            MatchExpressions: nil,
+        },
+    }
 
-	assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+    request := v1beta1.AdmissionRequest{
+        Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
+    }
 
-	// TODO: MatchExpressions tests should be done
-}
\ No newline at end of file
+    objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+
+    objectByteArray = []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label3":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+    assertEq(t, false, webhooks.IsRuleApplicableToRequest(resource, &request))
+
+    resource = types.PolicyResource{
+        Kind: "ConfigMap",
+        Selector: &metav1.LabelSelector{
+            MatchLabels: map[string]string{
+                "label3": "test1",
+                "label2": "test2",
+            },
+            MatchExpressions: nil,
+        },
+    }
+
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+}
+
+func TestIsRuleResourceFitsRequest_MatchLabelsAndMatchExpressions(t *testing.T) {
+    request := v1beta1.AdmissionRequest{
+        Kind: metav1.GroupVersionKind{Kind: "ConfigMap"},
+    }
+
+    resource := types.PolicyResource{
+        Kind: "ConfigMap",
+        Selector: &metav1.LabelSelector{
+            MatchLabels: map[string]string{
+                "label1": "test1",
+            },
+            MatchExpressions: []metav1.LabelSelectorRequirement{
+                metav1.LabelSelectorRequirement{
+                    Key:      "label2",
+                    Operator: "In",
+                    Values: []string{
+                        "test2",
+                    },
+                },
+            },
+        },
+    }
+
+    objectByteArray := []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+
+    resource = types.PolicyResource{
+        Kind: "ConfigMap",
+        Selector: &metav1.LabelSelector{
+            MatchLabels: map[string]string{
+                "label1": "test1",
+            },
+            MatchExpressions: []metav1.LabelSelectorRequirement{
+                metav1.LabelSelectorRequirement{
+                    Key:      "label2",
+                    Operator: "NotIn",
+                    Values: []string{
+                        "sometest1",
+                    },
+                },
+            },
+        },
+    }
+
+    objectByteArray = []byte(`{"metadata":{"name":"test-config-map","namespace":"default","creationTimestamp":null,"labels":{"label1":"test1","label2":"test2"}}}`)
+    request.Object.Raw = objectByteArray
+
+    assertEq(t, true, webhooks.IsRuleApplicableToRequest(resource, &request))
+}
diff --git a/webhooks/mutation.go b/webhooks/mutation.go
index 1fd415a7fe..ce43642f91 100644
--- a/webhooks/mutation.go
+++ b/webhooks/mutation.go
@@ -1,126 +1,132 @@
 package webhooks
 
 import (
-	"encoding/json"
-	"errors"
-	"log"
+    "encoding/json"
+    "errors"
+    "log"
 
-	types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
-	v1beta1 "k8s.io/api/admission/v1beta1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
+    v1beta1 "k8s.io/api/admission/v1beta1"
+    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// MutationWebhook is a data type that represents
+// buisness logic for resource mutation
 type MutationWebhook struct {
-	logger *log.Logger
+    logger *log.Logger
 }
 
+// NewMutationWebhook is a method that returns new instance
+// of MutationWebhook struct
 func NewMutationWebhook(logger *log.Logger) (*MutationWebhook, error) {
-	if logger == nil {
-		return nil, errors.New("Logger must be set for the mutation webhook")
-	}
-	return &MutationWebhook{logger: logger}, nil
+    if logger == nil {
+        return nil, errors.New("Logger must be set for the mutation webhook")
+    }
+    return &MutationWebhook{logger: logger}, nil
 }
 
+// Mutate applies admission to request
 func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest, policies []types.Policy) *v1beta1.AdmissionResponse {
-	mw.logger.Printf("AdmissionReview for Kind=%v, Namespace=%v Name=%v UID=%v patchOperation=%v UserInfo=%v",
-		request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation, request.UserInfo)
+    mw.logger.Printf("AdmissionReview for Kind=%v, Namespace=%v Name=%v UID=%v patchOperation=%v UserInfo=%v",
+        request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation, request.UserInfo)
 
-	if len(policies) == 0 {
-		return nil
-	}
+    if len(policies) == 0 {
+        return nil
+    }
 
-	var allPatches []types.PolicyPatch
-	for _, policy := range policies {
-		var stopOnError bool = true
-		if policy.Spec.FailurePolicy != nil && *policy.Spec.FailurePolicy == "continueOnError" {
-			stopOnError = false
-		}
+    var allPatches []types.PolicyPatch
+    for _, policy := range policies {
+        stopOnError := true
+        if policy.Spec.FailurePolicy != nil && *policy.Spec.FailurePolicy == "continueOnError" {
+            stopOnError = false
+        }
 
-		for ruleIdx, rule := range policy.Spec.Rules {
-			if IsRuleApplicableToRequest(rule.Resource, request) {
-				mw.logger.Printf("Applying policy %v, rule index = %v", policy.ObjectMeta.Name, ruleIdx)
-				rulePatches, err := mw.applyPolicyRule(request, rule)
-				/*
-				 * If at least one error is detected in the rule, the entire rule will not be applied.
-				 * This may be changed in the future by varying the policy.Spec.FailurePolicy values.
-				 */
-				if err != nil {
-					mw.logger.Printf("Error occurred while applying the policy: %v", err)
-					if stopOnError {
-						mw.logger.Printf("/!\\ Denying the request according to FailurePolicy spec /!\\")
-						return errorToResponse(err, false)
-					}
-				} else {
-					mw.logger.Printf("Prepared %v patches", len(rulePatches))
-					allPatches = append(allPatches, rulePatches...)
-				}
-			}
-		}
-	}
+        for ruleIdx, rule := range policy.Spec.Rules {
+            if IsRuleApplicableToRequest(rule.Resource, request) {
+                mw.logger.Printf("Applying policy %v, rule index = %v", policy.ObjectMeta.Name, ruleIdx)
+                rulePatches, err := mw.applyPolicyRule(request, rule)
+                /*
+                 * If at least one error is detected in the rule, the entire rule will not be applied.
+                 * This may be changed in the future by varying the policy.Spec.FailurePolicy values.
+                 */
+                if err != nil {
+                    mw.logger.Printf("Error occurred while applying the policy: %v", err)
+                    if stopOnError {
+                        mw.logger.Printf("/!\\ Denying the request according to FailurePolicy spec /!\\")
+                        return errorToResponse(err, false)
+                    }
+                } else {
+                    mw.logger.Printf("Prepared %v patches", len(rulePatches))
+                    allPatches = append(allPatches, rulePatches...)
+                }
+            }
+        }
+    }
 
-	patchesBytes, err := SerializePatches(allPatches)
-	if err != nil {
-		mw.logger.Printf("Error occerred while serializing JSONPathch: %v", err)
-		return errorToResponse(err, true)
-	}
+    patchesBytes, err := SerializePatches(allPatches)
+    if err != nil {
+        mw.logger.Printf("Error occerred while serializing JSONPathch: %v", err)
+        return errorToResponse(err, true)
+    }
 
-	return &v1beta1.AdmissionResponse{
-		Allowed: true,
-		Patch:   patchesBytes,
-		PatchType: func() *v1beta1.PatchType {
-			pt := v1beta1.PatchTypeJSONPatch
-			return &pt
-		}(),
-	}
+    return &v1beta1.AdmissionResponse{
+        Allowed: true,
+        Patch:   patchesBytes,
+        PatchType: func() *v1beta1.PatchType {
+            pt := v1beta1.PatchTypeJSONPatch
+            return &pt
+        }(),
+    }
 }
 
 // Applies all possible patches in a rule
 func (mw *MutationWebhook) applyPolicyRule(request *v1beta1.AdmissionRequest, rule types.PolicyRule) ([]types.PolicyPatch, error) {
-	var allPatches []types.PolicyPatch
-	if rule.Patches == nil && rule.ConfigMapGenerator == nil && rule.SecretGenerator == nil {
-		return nil, errors.New("The rule is empty!")
-	}
+    var allPatches []types.PolicyPatch
+    if rule.Patches == nil && rule.ConfigMapGenerator == nil && rule.SecretGenerator == nil {
+        return nil, errors.New("The rule is empty")
+    }
 
-	allPatches = append(allPatches, rule.Patches...)
+    allPatches = append(allPatches, rule.Patches...)
 
-	if rule.ConfigMapGenerator != nil {
-		// TODO: Make patches from configMapGenerator and add them to returned array
-	}
+    if rule.ConfigMapGenerator != nil {
+        // TODO: Make patches from configMapGenerator and add them to returned array
+    }
 
-	if rule.SecretGenerator != nil {
-		// TODO: Make patches from secretGenerator and add them to returned array
-	}
+    if rule.SecretGenerator != nil {
+        // TODO: Make patches from secretGenerator and add them to returned array
+    }
 
-	return allPatches, nil
+    return allPatches, nil
 }
 
+// SerializePatches converts JSON patches to byte array
 func SerializePatches(patches []types.PolicyPatch) ([]byte, error) {
-	var result []byte
-	result = append(result, []byte("[\n")...)
-	for index, patch := range patches {
-		if patch.Operation == "" || patch.Path == "" {
-			return nil, errors.New("JSONPatch doesn't contain mandatory fields 'path' or 'op'")
-		}
+    var result []byte
+    result = append(result, []byte("[\n")...)
+    for index, patch := range patches {
+        if patch.Operation == "" || patch.Path == "" {
+            return nil, errors.New("JSONPatch doesn't contain mandatory fields 'path' or 'op'")
+        }
 
-		patchBytes, err := json.Marshal(patch)
-		if err != nil {
-			return nil, err
-		}
+        patchBytes, err := json.Marshal(patch)
+        if err != nil {
+            return nil, err
+        }
 
-		result = append(result, patchBytes...)
-		if index != (len(patches) - 1) {
-			result = append(result, []byte(",\n")...)
-		}
-	}
-	result = append(result, []byte("\n]")...)
-	return result, nil
+        result = append(result, patchBytes...)
+        if index != (len(patches) - 1) {
+            result = append(result, []byte(",\n")...)
+        }
+    }
+    result = append(result, []byte("\n]")...)
+    return result, nil
 }
 
 func errorToResponse(err error, allowed bool) *v1beta1.AdmissionResponse {
-	return &v1beta1.AdmissionResponse{
-		Result: &metav1.Status{
-			Message: err.Error(),
-		},
-		Allowed: allowed,
-	}
+    return &v1beta1.AdmissionResponse{
+        Result: &metav1.Status{
+            Message: err.Error(),
+        },
+        Allowed: allowed,
+    }
 }
diff --git a/webhooks/mutation_test.go b/webhooks/mutation_test.go
index 06ddb54787..1d8a0efe11 100644
--- a/webhooks/mutation_test.go
+++ b/webhooks/mutation_test.go
@@ -1,48 +1,48 @@
 package webhooks_test
 
 import (
-	"testing"
+    "testing"
 
-	"github.com/nirmata/kube-policy/webhooks"
+    "github.com/nirmata/kube-policy/webhooks"
 
-	//v1beta1 "k8s.io/api/admission/v1beta1"
-	//metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
+    //v1beta1 "k8s.io/api/admission/v1beta1"
+    //metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
 )
 
 func TestSerializePatches_Empty(t *testing.T) {
-	var patches []types.PolicyPatch
-	bytes, err := webhooks.SerializePatches(patches)
-	assertEq(t, nil, err)
-	assertEqStringAndData(t, "[\n\n]", bytes)
+    var patches []types.PolicyPatch
+    bytes, err := webhooks.SerializePatches(patches)
+    assertEq(t, nil, err)
+    assertEqStringAndData(t, "[\n\n]", bytes)
 }
 
 func TestSerializePatches_SingleValid(t *testing.T) {
-	patch := types.PolicyPatch{
-		Path:      "/metadata/labels/is-mutated",
-		Operation: "add",
-		Value:     "true",
-	}
-	patches := []types.PolicyPatch{patch}
-	bytes, err := webhooks.SerializePatches(patches)
-	assertEq(t, nil, err)
-	assertEqStringAndData(t, `[
+    patch := types.PolicyPatch{
+        Path:      "/metadata/labels/is-mutated",
+        Operation: "add",
+        Value:     "true",
+    }
+    patches := []types.PolicyPatch{patch}
+    bytes, err := webhooks.SerializePatches(patches)
+    assertEq(t, nil, err)
+    assertEqStringAndData(t, `[
 {"path":"/metadata/labels/is-mutated","op":"add","value":"true"}
 ]`, bytes)
 }
 
 func TestSerializePatches_SingleInvalid(t *testing.T) {
-	patch := types.PolicyPatch{
-		Path:  "/metadata/labels/is-mutated",
-		Value: "true",
-	}
-	patches := []types.PolicyPatch{patch}
-	_, err := webhooks.SerializePatches(patches)
-	assertNe(t, nil, err)
-	patches[0].Path = ""
-	patches[0].Operation = "delete"
-	_, err = webhooks.SerializePatches(patches)
-	assertNe(t, nil, err)
+    patch := types.PolicyPatch{
+        Path:  "/metadata/labels/is-mutated",
+        Value: "true",
+    }
+    patches := []types.PolicyPatch{patch}
+    _, err := webhooks.SerializePatches(patches)
+    assertNe(t, nil, err)
+    patches[0].Path = ""
+    patches[0].Operation = "delete"
+    _, err = webhooks.SerializePatches(patches)
+    assertNe(t, nil, err)
 }
 
 // patch := `[ {"op":"add","path":"/metadata/labels","value":{"is-mutated":"true"}} ]`
diff --git a/webhooks/utils_test.go b/webhooks/utils_test.go
index 4b03350431..2ad348d3a2 100644
--- a/webhooks/utils_test.go
+++ b/webhooks/utils_test.go
@@ -1,38 +1,38 @@
 package webhooks_test
 
 import (
-	"testing"
+    "testing"
 )
 
 func assertEq(t *testing.T, expected interface{}, actual interface{}) {
-	if expected != actual {
-		t.Errorf("%s != %s", expected, actual)
-	}
+    if expected != actual {
+        t.Errorf("%s != %s", expected, actual)
+    }
 }
 
 func assertNe(t *testing.T, expected interface{}, actual interface{}) {
-	if expected == actual {
-		t.Errorf("%s != %s", expected, actual)
-	}
+    if expected == actual {
+        t.Errorf("%s != %s", expected, actual)
+    }
 }
 
 func assertEqDataImpl(t *testing.T, expected, actual []byte, formatModifier string) {
-	if len(expected) != len(actual) {
-		t.Errorf("len(expected) != len(actual): %d != %d\n1:"+formatModifier+"\n2:"+formatModifier, len(expected), len(actual), expected, actual)
-		return
-	}
+    if len(expected) != len(actual) {
+        t.Errorf("len(expected) != len(actual): %d != %d\n1:"+formatModifier+"\n2:"+formatModifier, len(expected), len(actual), expected, actual)
+        return
+    }
 
-	for idx, val := range actual {
-		if val != expected[idx] {
-			t.Errorf("Slices not equal at index %d:\n1:"+formatModifier+"\n2:"+formatModifier, idx, expected, actual)
-		}
-	}
+    for idx, val := range actual {
+        if val != expected[idx] {
+            t.Errorf("Slices not equal at index %d:\n1:"+formatModifier+"\n2:"+formatModifier, idx, expected, actual)
+        }
+    }
 }
 
 func assertEqData(t *testing.T, expected, actual []byte) {
-	assertEqDataImpl(t, expected, actual, "%x")
+    assertEqDataImpl(t, expected, actual, "%x")
 }
 
 func assertEqStringAndData(t *testing.T, str string, data []byte) {
-	assertEqDataImpl(t, []byte(str), data, "%s")
+    assertEqDataImpl(t, []byte(str), data, "%s")
 }