From 79999c49482796cae14a624a93095b6788953e38 Mon Sep 17 00:00:00 2001
From: shravan <shravan.ss@zopsmart.com>
Date: Fri, 17 Jan 2020 00:05:15 +0530
Subject: [PATCH] extended cli

---
 Makefile                                      |   1 -
 cmd/cli/kyverno/main.go                       |   9 +
 cmd/cli/main.go                               |  25 --
 definitions/install.yaml                      |   4 +-
 pkg/config/config.go                          |   2 +-
 pkg/engine/mutate/overlay.go                  |   4 +-
 pkg/engine/mutation.go                        |   4 +-
 pkg/engine/utils/utils.go                     |   3 +-
 pkg/kyverno/apply/apply.go                    | 251 ----------------
 pkg/kyverno/apply/command.go                  | 267 ++++++++++++++++++
 pkg/kyverno/apply/util.go                     | 105 -------
 pkg/kyverno/cmd.go                            |  27 --
 pkg/kyverno/main.go                           |  48 ++++
 pkg/kyverno/validate/command.go               |  64 +++++
 pkg/kyverno/version/command.go                |  21 ++
 pkg/kyverno/version/version.go                |  29 --
 pkg/webhookconfig/common.go                   |   4 -
 pkg/webhooks/mutation.go                      |   2 -
 .../disallow_default_namespace.yaml           |   1 -
 19 files changed, 417 insertions(+), 454 deletions(-)
 create mode 100644 cmd/cli/kyverno/main.go
 delete mode 100644 cmd/cli/main.go
 delete mode 100644 pkg/kyverno/apply/apply.go
 create mode 100644 pkg/kyverno/apply/command.go
 delete mode 100644 pkg/kyverno/apply/util.go
 delete mode 100644 pkg/kyverno/cmd.go
 create mode 100644 pkg/kyverno/main.go
 create mode 100644 pkg/kyverno/validate/command.go
 create mode 100644 pkg/kyverno/version/command.go
 delete mode 100644 pkg/kyverno/version/version.go

diff --git a/Makefile b/Makefile
index 506f4fb2a1..732a1facce 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,6 @@ REGISTRY=index.docker.io
 REPO=$(REGISTRY)/nirmata/kyverno
 IMAGE_TAG=$(GIT_VERSION)
 GOOS ?= $(shell go env GOOS)
-PACKAGE ?=github.com/nirmata/kyverno
 LD_FLAGS="-s -w -X $(PACKAGE)/pkg/version.BuildVersion=$(GIT_VERSION) -X $(PACKAGE)/pkg/version.BuildHash=$(GIT_HASH) -X $(PACKAGE)/pkg/version.BuildTime=$(TIMESTAMP)"
 
 ##################################
diff --git a/cmd/cli/kyverno/main.go b/cmd/cli/kyverno/main.go
new file mode 100644
index 0000000000..a5adfa5a9e
--- /dev/null
+++ b/cmd/cli/kyverno/main.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+	"github.com/nirmata/kyverno/pkg/kyverno"
+)
+
+func main() {
+	kyverno.CLI()
+}
diff --git a/cmd/cli/main.go b/cmd/cli/main.go
deleted file mode 100644
index 33bc524e9c..0000000000
--- a/cmd/cli/main.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package main
-
-import (
-	goflag "flag"
-	"fmt"
-	"os"
-
-	"github.com/nirmata/kyverno/pkg/config"
-	kyverno "github.com/nirmata/kyverno/pkg/kyverno"
-	flag "github.com/spf13/pflag"
-)
-
-func main() {
-	cmd := kyverno.NewDefaultKyvernoCommand()
-	if err := cmd.Execute(); err != nil {
-		fmt.Fprintf(os.Stderr, "%v\n", err)
-		os.Exit(1)
-	}
-}
-
-func init() {
-	flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
-	config.LogDefaultFlags()
-	flag.Parse()
-}
diff --git a/definitions/install.yaml b/definitions/install.yaml
index 8e5b660096..fd7fc1a58b 100644
--- a/definitions/install.yaml
+++ b/definitions/install.yaml
@@ -520,10 +520,10 @@ spec:
       serviceAccountName: kyverno-service-account
       initContainers:
         - name: kyverno-pre
-          image: nirmata/kyvernopre:v1.1.1
+          image: nirmata/kyvernopre:v1.1.0
       containers:
         - name: kyverno
-          image: nirmata/kyverno:v1.1.1
+          image: nirmata/kyverno:v1.1.0
           args:
           - "--filterK8Resources=[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][*,kyverno,*]"
           # customize webhook timout
diff --git a/pkg/config/config.go b/pkg/config/config.go
index f553fa8122..c975a1cea7 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -83,6 +83,6 @@ func CreateClientConfig(kubeconfig string) (*rest.Config, error) {
 		glog.Info("Using in-cluster configuration")
 		return rest.InClusterConfig()
 	}
-	glog.Infof("Using configuration from '%s'", kubeconfig)
+	glog.V(4).Infof("Using configuration from '%s'", kubeconfig)
 	return clientcmd.BuildConfigFromFlags("", kubeconfig)
 }
diff --git a/pkg/engine/mutate/overlay.go b/pkg/engine/mutate/overlay.go
index 59d1f50865..51b0640b25 100644
--- a/pkg/engine/mutate/overlay.go
+++ b/pkg/engine/mutate/overlay.go
@@ -387,11 +387,11 @@ func preparePath(path string) string {
 	}
 
 	annPath := "/metadata/annotations/"
+	idx := strings.Index(path, annPath)
 	// escape slash in annotation patch
 	if strings.Contains(path, annPath) {
-		idx := strings.Index(path, annPath)
 		p := path[idx+len(annPath):]
-		path = path[:idx+len(annPath)] + strings.ReplaceAll(p, "/", "~1")
+		path = annPath + strings.ReplaceAll(p, "/", "~1")
 	}
 	return path
 }
diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go
index a8c36b7262..ee0cc32295 100644
--- a/pkg/engine/mutation.go
+++ b/pkg/engine/mutation.go
@@ -105,7 +105,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
 					continue
 				}
 
-				glog.Infof("Mutate overlay in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
+				glog.V(4).Infof("Mutate overlay in rule '%s' successfully applied on %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
 			}
 
 			resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
@@ -156,7 +156,7 @@ var podTemplateRule = kyverno.Rule{
 				"template": map[string]interface{}{
 					"metadata": map[string]interface{}{
 						"annotations": map[string]interface{}{
-							"+(pod-policies.kyverno.io/autogen-applied)": "true",
+							"pod-policies.kyverno.io/autogen-applied": "true",
 						},
 					},
 				},
diff --git a/pkg/engine/utils/utils.go b/pkg/engine/utils/utils.go
index 8dbb1bec26..de103fe930 100644
--- a/pkg/engine/utils/utils.go
+++ b/pkg/engine/utils/utils.go
@@ -25,12 +25,11 @@ func (ri RuleType) String() string {
 }
 
 // ApplyPatches patches given resource with given patches and returns patched document
-// return origin resource if any error occurs
 func ApplyPatches(resource []byte, patches [][]byte) ([]byte, error) {
 	joinedPatches := JoinPatches(patches)
 	patch, err := jsonpatch.DecodePatch(joinedPatches)
 	if err != nil {
-		return resource, err
+		return nil, err
 	}
 
 	patchedDocument, err := patch.Apply(resource)
diff --git a/pkg/kyverno/apply/apply.go b/pkg/kyverno/apply/apply.go
deleted file mode 100644
index bbdbdb6e71..0000000000
--- a/pkg/kyverno/apply/apply.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package apply
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"io"
-	"os"
-
-	"github.com/golang/glog"
-	kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
-	"github.com/nirmata/kyverno/pkg/engine"
-	"github.com/spf13/cobra"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/runtime"
-	schema "k8s.io/apimachinery/pkg/runtime/schema"
-	yaml "k8s.io/apimachinery/pkg/util/yaml"
-	memory "k8s.io/client-go/discovery/cached/memory"
-	dynamic "k8s.io/client-go/dynamic"
-	kubernetes "k8s.io/client-go/kubernetes"
-	"k8s.io/client-go/kubernetes/scheme"
-	"k8s.io/client-go/restmapper"
-)
-
-const (
-	applyExample = `  # Apply a policy to the resource.
-  kyverno apply @policy.yaml @resource.yaml
-  kyverno apply @policy.yaml @resourceDir/
-  kyverno apply @policy.yaml @resource.yaml --kubeconfig=$PATH_TO_KUBECONFIG_FILE`
-
-	defaultYamlSeparator = "---"
-)
-
-// NewCmdApply returns the apply command for kyverno
-func NewCmdApply(in io.Reader, out, errout io.Writer) *cobra.Command {
-	var kubeconfig string
-	cmd := &cobra.Command{
-		Use:     "apply",
-		Short:   "Apply policy on the resource(s)",
-		Example: applyExample,
-		Run: func(cmd *cobra.Command, args []string) {
-			policy, resources := complete(kubeconfig, args)
-			output := applyPolicy(policy, resources)
-			fmt.Printf("%v\n", output)
-		},
-	}
-
-	cmd.Flags().StringVar(&kubeconfig, "kubeconfig", "", "path to kubeconfig file")
-	return cmd
-}
-
-func complete(kubeconfig string, args []string) (*kyverno.ClusterPolicy, []*resourceInfo) {
-	policyDir, resourceDir, err := validateDir(args)
-	if err != nil {
-		glog.Errorf("Failed to parse file path, err: %v\n", err)
-		os.Exit(1)
-	}
-
-	// extract policy
-	policy, err := extractPolicy(policyDir)
-	if err != nil {
-		glog.Errorf("Failed to extract policy: %v\n", err)
-		os.Exit(1)
-	}
-
-	// extract rawResource
-	resources, err := extractResource(resourceDir, kubeconfig)
-	if err != nil {
-		glog.Errorf("Failed to parse resource: %v", err)
-		os.Exit(1)
-	}
-
-	return policy, resources
-}
-
-func applyPolicy(policy *kyverno.ClusterPolicy, resources []*resourceInfo) (output string) {
-	for _, resource := range resources {
-		patchedDocument, err := applyPolicyOnRaw(policy, resource.rawResource, resource.gvk)
-		if err != nil {
-			glog.Errorf("Error applying policy on resource %s, err: %v\n", resource.gvk.Kind, err)
-			continue
-		}
-
-		out, err := prettyPrint(patchedDocument)
-		if err != nil {
-			glog.Errorf("JSON parse error: %v\n", err)
-			continue
-		}
-
-		output = output + fmt.Sprintf("---\n%s", string(out))
-	}
-	return
-}
-
-func applyPolicyOnRaw(policy *kyverno.ClusterPolicy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]byte, error) {
-	patchedResource := rawResource
-	var err error
-
-	rname := engine.ParseNameFromObject(rawResource)
-	rns := engine.ParseNamespaceFromObject(rawResource)
-	resource, err := ConvertToUnstructured(rawResource)
-	if err != nil {
-		return nil, err
-	}
-	//TODO check if the kind information is present resource
-	// Process Mutation
-	engineResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource})
-	if !engineResponse.IsSuccesful() {
-		glog.Infof("Failed to apply policy %s on resource %s/%s", policy.Name, rname, rns)
-		for _, r := range engineResponse.PolicyResponse.Rules {
-			glog.Warning(r.Message)
-		}
-	} else if len(engineResponse.PolicyResponse.Rules) > 0 {
-		glog.Infof("Mutation from policy %s has applied succesfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
-
-		// Process Validation
-		engineResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: *resource})
-
-		if !engineResponse.IsSuccesful() {
-			glog.Infof("Failed to apply policy %s on resource %s/%s", policy.Name, rname, rns)
-			for _, r := range engineResponse.PolicyResponse.Rules {
-				glog.Warning(r.Message)
-			}
-			return patchedResource, fmt.Errorf("policy %s on resource %s/%s not satisfied", policy.Name, rname, rns)
-		} else if len(engineResponse.PolicyResponse.Rules) > 0 {
-			glog.Infof("Validation from policy %s has applied succesfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
-		}
-	}
-	return patchedResource, nil
-}
-
-func extractPolicy(fileDir string) (*kyverno.ClusterPolicy, error) {
-	policy := &kyverno.ClusterPolicy{}
-
-	file, err := loadFile(fileDir)
-	if err != nil {
-		return nil, fmt.Errorf("failed to load file: %v", err)
-	}
-
-	policyBytes, err := yaml.ToJSON(file)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := json.Unmarshal(policyBytes, policy); err != nil {
-		return nil, fmt.Errorf("failed to decode policy %s, err: %v", policy.Name, err)
-	}
-
-	if policy.TypeMeta.Kind != "ClusterPolicy" {
-		return nil, fmt.Errorf("failed to parse policy")
-	}
-
-	return policy, nil
-}
-
-type resourceInfo struct {
-	rawResource []byte
-	gvk         *metav1.GroupVersionKind
-}
-
-func extractResource(fileDir, kubeconfig string) ([]*resourceInfo, error) {
-	var files []string
-	var resources []*resourceInfo
-
-	// check if applied on multiple resources
-	isDir, err := isDir(fileDir)
-	if err != nil {
-		return nil, err
-	}
-
-	if isDir {
-		files, err = scanDir(fileDir)
-		if err != nil {
-			return nil, err
-		}
-	} else {
-		files = []string{fileDir}
-	}
-
-	for _, dir := range files {
-		data, err := loadFile(dir)
-		if err != nil {
-			glog.Warningf("Error while loading file: %v\n", err)
-			continue
-		}
-
-		dd := bytes.Split(data, []byte(defaultYamlSeparator))
-
-		for _, d := range dd {
-			decode := scheme.Codecs.UniversalDeserializer().Decode
-			obj, gvk, err := decode([]byte(d), nil, nil)
-			if err != nil {
-				glog.Warningf("Error while decoding YAML object, err: %s\n", err)
-				continue
-			}
-
-			actualObj, err := convertToActualObject(kubeconfig, gvk, obj)
-			if err != nil {
-				glog.V(3).Infof("Failed to convert resource %s to actual k8s object: %v\n", gvk.Kind, err)
-				glog.V(3).Infof("Apply policy on raw resource.\n")
-			}
-
-			raw, err := json.Marshal(actualObj)
-			if err != nil {
-				glog.Warningf("Error while marshalling manifest, err: %v\n", err)
-				continue
-			}
-
-			gvkInfo := &metav1.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind}
-			resources = append(resources, &resourceInfo{rawResource: raw, gvk: gvkInfo})
-		}
-	}
-
-	return resources, err
-}
-
-func convertToActualObject(kubeconfig string, gvk *schema.GroupVersionKind, obj runtime.Object) (interface{}, error) {
-	clientConfig, err := createClientConfig(kubeconfig)
-	if err != nil {
-		return obj, err
-	}
-
-	dynamicClient, err := dynamic.NewForConfig(clientConfig)
-	if err != nil {
-		return obj, err
-	}
-
-	kclient, err := kubernetes.NewForConfig(clientConfig)
-	if err != nil {
-		return obj, err
-	}
-
-	asUnstructured := &unstructured.Unstructured{}
-	if err := scheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
-		return obj, err
-	}
-
-	mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(kclient.Discovery()))
-	mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
-	if err != nil {
-		return obj, err
-	}
-
-	actualObj, err := dynamicClient.Resource(mapping.Resource).Namespace("default").Create(asUnstructured, metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}})
-	if err != nil {
-		return obj, err
-	}
-
-	return actualObj, nil
-}
diff --git a/pkg/kyverno/apply/command.go b/pkg/kyverno/apply/command.go
new file mode 100644
index 0000000000..bedc2e2ee9
--- /dev/null
+++ b/pkg/kyverno/apply/command.go
@@ -0,0 +1,267 @@
+package apply
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"strings"
+
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
+	"github.com/nirmata/kyverno/pkg/config"
+	"k8s.io/client-go/discovery"
+
+	"k8s.io/apimachinery/pkg/util/yaml"
+
+	"github.com/nirmata/kyverno/pkg/engine"
+
+	engineutils "github.com/nirmata/kyverno/pkg/engine/utils"
+
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+
+	v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
+	"github.com/spf13/cobra"
+	yamlv2 "gopkg.in/yaml.v2"
+	"k8s.io/client-go/kubernetes/scheme"
+)
+
+func Command() *cobra.Command {
+	var resourcePath, kubeConfig string
+
+	cmd := &cobra.Command{
+		Use:     "apply",
+		Short:   "Applies policies on resources",
+		Example: fmt.Sprintf("To apply on a resource:\nkyverno apply /path/to/policy1 /path/to/policy2 --resource=/path/to/resource\n\nTo apply on a cluster\nkyverno apply /path/to/policy1 /path/to/policy2 --kubeConfig=/path/to/kubeConfig"),
+		RunE: func(cmd *cobra.Command, policyPaths []string) error {
+			if resourcePath == "" && kubeConfig == "" {
+				fmt.Println("Specify path to resource file or kube config")
+			}
+
+			var policies []*v1.ClusterPolicy
+			for _, policyPath := range policyPaths {
+				policy, err := getPolicy(policyPath)
+				if err != nil {
+					return err
+				}
+
+				policies = append(policies, policy)
+			}
+
+			resources, err := getResources(policies, kubeConfig, resourcePath)
+			if err != nil {
+				return err
+			}
+
+			for i, policy := range policies {
+				for j, resource := range resources {
+					if !(j == 0 && i == 0) {
+						fmt.Printf("\n\n=======================================================================\n")
+					}
+
+					err = applyPolicyOnResource(policy, resource)
+					if err != nil {
+						return err
+					}
+				}
+			}
+
+			return nil
+		},
+	}
+
+	cmd.Flags().StringVar(&resourcePath, "resource", "", "path to resource file")
+	cmd.Flags().StringVar(&kubeConfig, "kubeConfig", "", "path to .kube/config file")
+	return cmd
+}
+
+func getResources(policies []*v1.ClusterPolicy, kubeConfig, resourcePath string) ([]*unstructured.Unstructured, error) {
+	var resources []*unstructured.Unstructured
+	var err error
+
+	if kubeConfig != "" {
+		var resourceTypesMap = make(map[string]bool)
+		var resourceTypes []string
+		for _, policy := range policies {
+			for _, rule := range policy.Spec.Rules {
+				for _, kind := range rule.MatchResources.Kinds {
+					resourceTypesMap[kind] = true
+				}
+			}
+		}
+
+		for kind := range resourceTypesMap {
+			resourceTypes = append(resourceTypes, kind)
+		}
+
+		resources, err = getResourcesOfTypeFromCluster(resourceTypes, kubeConfig)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if resourcePath != "" {
+		resource, err := getResource(resourcePath)
+		if err != nil {
+			return nil, err
+		}
+
+		resources = append(resources, resource)
+	}
+
+	return resources, nil
+}
+
+func getResourcesOfTypeFromCluster(resourceTypes []string, kubeConfig string) ([]*unstructured.Unstructured, error) {
+	var resources []*unstructured.Unstructured
+
+	clientConfig, err := config.CreateClientConfig(kubeConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	dClient, err := discovery.NewDiscoveryClientForConfig(clientConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	//var kindToListApi = map[string]string{
+	//	"pod": "/api/v1/pods",
+	//	"services": "/api/v1/services",
+	//}
+
+	for _, kind := range resourceTypes {
+		listObjectRaw, err := dClient.RESTClient().Get().RequestURI("/api/v1/" + strings.ToLower(kind) + "s").Do().Raw()
+		if err != nil {
+			log.Println(2, err)
+		}
+
+		listObject, err := engineutils.ConvertToUnstructured(listObjectRaw)
+		if err != nil {
+			return nil, err
+		}
+
+		resourceList, err := listObject.ToList()
+		if err != nil {
+			return nil, err
+		}
+
+		version := resourceList.GetAPIVersion()
+		for _, resource := range resourceList.Items {
+			resource.SetGroupVersionKind(schema.GroupVersionKind{
+				Group:   "",
+				Version: version,
+				Kind:    kind,
+			})
+			resources = append(resources, resource.DeepCopy())
+		}
+	}
+
+	return resources, nil
+}
+
+func getPolicy(path string) (*v1.ClusterPolicy, error) {
+	policy := &v1.ClusterPolicy{}
+
+	file, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, fmt.Errorf("failed to load file: %v", err)
+	}
+
+	policyBytes, err := yaml.ToJSON(file)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := json.Unmarshal(policyBytes, policy); err != nil {
+		return nil, fmt.Errorf("failed to decode policy %s, err: %v", policy.Name, err)
+	}
+
+	if policy.TypeMeta.Kind != "ClusterPolicy" {
+		return nil, fmt.Errorf("failed to parse policy")
+	}
+
+	return policy, nil
+}
+
+func getResource(path string) (*unstructured.Unstructured, error) {
+
+	resourceYaml, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	decode := scheme.Codecs.UniversalDeserializer().Decode
+	resourceObject, metaData, err := decode(resourceYaml, nil, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	resourceUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&resourceObject)
+	if err != nil {
+		return nil, err
+	}
+
+	resourceJSON, err := json.Marshal(resourceUnstructured)
+	if err != nil {
+		return nil, err
+	}
+
+	resource, err := engineutils.ConvertToUnstructured(resourceJSON)
+	if err != nil {
+		return nil, err
+	}
+
+	resource.SetGroupVersionKind(*metaData)
+
+	if resource.GetNamespace() == "" {
+		resource.SetNamespace("default")
+	}
+
+	return resource, nil
+}
+
+func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured) error {
+
+	fmt.Printf("\n\nApplying Policy %s on Resource %s/%s/%s/%s", policy.Name, resource.GetNamespace(), resource.GetKind(), resource.GetName(), resource.GetUID())
+
+	mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource})
+	if !mutateResponse.IsSuccesful() {
+		fmt.Printf("\n\nMutation:")
+		fmt.Printf("\nFailed to apply mutation")
+		for i, r := range mutateResponse.PolicyResponse.Rules {
+			fmt.Printf("\n%d. %s", i+1, r.Message)
+		}
+		fmt.Printf("\n\n")
+	} else {
+		if len(mutateResponse.PolicyResponse.Rules) > 0 {
+			fmt.Printf("\n\nMutation:")
+			fmt.Printf("\nMutation has been applied succesfully")
+			yamlEncodedResource, err := yamlv2.Marshal(mutateResponse.PatchedResource.Object)
+			if err != nil {
+				return err
+			}
+
+			fmt.Printf("\n\n" + strings.ReplaceAll(string(yamlEncodedResource), "\n", "\n"))
+		}
+	}
+
+	validateResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource})
+	if !validateResponse.IsSuccesful() {
+		fmt.Printf("\n\nValidation:")
+		fmt.Printf("\nResource is invalid")
+		for i, r := range validateResponse.PolicyResponse.Rules {
+			fmt.Printf("\n%d. %s", i+1, r.Message)
+		}
+		fmt.Printf("\n\n")
+	} else {
+		if len(validateResponse.PolicyResponse.Rules) > 0 {
+			fmt.Printf("\n\nValidation:")
+			fmt.Printf("\nResource is valid")
+		}
+	}
+
+	return nil
+}
diff --git a/pkg/kyverno/apply/util.go b/pkg/kyverno/apply/util.go
deleted file mode 100644
index 26e0390300..0000000000
--- a/pkg/kyverno/apply/util.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package apply
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"github.com/golang/glog"
-	yamlv2 "gopkg.in/yaml.v2"
-	unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	rest "k8s.io/client-go/rest"
-	clientcmd "k8s.io/client-go/tools/clientcmd"
-)
-
-func createClientConfig(kubeconfig string) (*rest.Config, error) {
-	if kubeconfig == "" {
-		defaultKC := defaultKubeconfigPath()
-		if _, err := os.Stat(defaultKC); err == nil {
-			kubeconfig = defaultKC
-		}
-	}
-
-	return clientcmd.BuildConfigFromFlags("", kubeconfig)
-}
-
-func defaultKubeconfigPath() string {
-	home, err := os.UserHomeDir()
-	if err != nil {
-		glog.Warningf("Warning: failed to get home dir: %v\n", err)
-		return ""
-	}
-
-	return filepath.Join(home, ".kube", "config")
-}
-
-func loadFile(fileDir string) ([]byte, error) {
-	if _, err := os.Stat(fileDir); os.IsNotExist(err) {
-		return nil, err
-	}
-
-	return ioutil.ReadFile(fileDir)
-}
-
-func validateDir(args []string) (policyDir, resourceDir string, err error) {
-	if len(args) != 2 {
-		return "", "", fmt.Errorf("missing policy and/or resource manifest")
-	}
-
-	if strings.HasPrefix(args[0], "@") {
-		policyDir = args[0][1:]
-	}
-
-	if strings.HasPrefix(args[1], "@") {
-		resourceDir = args[1][1:]
-	}
-	return
-}
-
-func prettyPrint(data []byte) ([]byte, error) {
-	out := make(map[interface{}]interface{})
-	if err := yamlv2.Unmarshal(data, &out); err != nil {
-		return nil, err
-	}
-
-	return yamlv2.Marshal(&out)
-}
-
-func isDir(dir string) (bool, error) {
-	fi, err := os.Stat(dir)
-	if err != nil {
-		return false, err
-	}
-
-	return fi.IsDir(), nil
-}
-
-func scanDir(dir string) ([]string, error) {
-	var res []string
-
-	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return fmt.Errorf("prevent panic by handling failure accessing a path %q: %v", dir, err)
-		}
-
-		res = append(res, path)
-		return nil
-	})
-
-	if err != nil {
-		return nil, fmt.Errorf("error walking the path %q: %v", dir, err)
-	}
-
-	return res[1:], nil
-}
-func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
-	resource := &unstructured.Unstructured{}
-	err := resource.UnmarshalJSON(data)
-	if err != nil {
-		glog.V(4).Infof("failed to unmarshall resource: %v", err)
-		return nil, err
-	}
-	return resource, nil
-}
diff --git a/pkg/kyverno/cmd.go b/pkg/kyverno/cmd.go
deleted file mode 100644
index ac31e2a24f..0000000000
--- a/pkg/kyverno/cmd.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package cmd
-
-import (
-	"io"
-	"os"
-
-	"github.com/nirmata/kyverno/pkg/kyverno/apply"
-	"github.com/nirmata/kyverno/pkg/kyverno/version"
-	"github.com/spf13/cobra"
-)
-
-// NewDefaultKyvernoCommand ...
-func NewDefaultKyvernoCommand() *cobra.Command {
-	return NewKyvernoCommand(os.Stdin, os.Stdout, os.Stderr)
-}
-
-// NewKyvernoCommand returns the new kynerno command
-func NewKyvernoCommand(in io.Reader, out, errout io.Writer) *cobra.Command {
-	cmds := &cobra.Command{
-		Use:   "kyverno",
-		Short: "kyverno manages native policies of Kubernetes",
-	}
-
-	cmds.AddCommand(apply.NewCmdApply(in, out, errout))
-	cmds.AddCommand(version.NewCmdVersion(out))
-	return cmds
-}
diff --git a/pkg/kyverno/main.go b/pkg/kyverno/main.go
new file mode 100644
index 0000000000..43b1fd05a5
--- /dev/null
+++ b/pkg/kyverno/main.go
@@ -0,0 +1,48 @@
+package kyverno
+
+import (
+	"flag"
+	"os"
+
+	"github.com/nirmata/kyverno/pkg/kyverno/validate"
+
+	"github.com/nirmata/kyverno/pkg/kyverno/apply"
+
+	"github.com/nirmata/kyverno/pkg/kyverno/version"
+
+	"github.com/spf13/cobra"
+)
+
+func CLI() {
+	cli := &cobra.Command{
+		Use:   "kyverno",
+		Short: "kyverno manages native policies of Kubernetes",
+	}
+
+	configureGlog(cli)
+
+	commands := []*cobra.Command{
+		version.Command(),
+		apply.Command(),
+		validate.Command(),
+	}
+
+	cli.AddCommand(commands...)
+
+	if err := cli.Execute(); err != nil {
+		os.Exit(1)
+	}
+}
+
+func configureGlog(cli *cobra.Command) {
+	flag.Parse()
+	flag.Set("logtostderr", "true")
+
+	cli.PersistentFlags().AddGoFlagSet(flag.CommandLine)
+	cli.PersistentFlags().MarkHidden("alsologtostderr")
+	cli.PersistentFlags().MarkHidden("logtostderr")
+	cli.PersistentFlags().MarkHidden("log_dir")
+	cli.PersistentFlags().MarkHidden("log_backtrace_at")
+	cli.PersistentFlags().MarkHidden("stderrthreshold")
+	cli.PersistentFlags().MarkHidden("vmodule")
+}
diff --git a/pkg/kyverno/validate/command.go b/pkg/kyverno/validate/command.go
new file mode 100644
index 0000000000..b792ca171a
--- /dev/null
+++ b/pkg/kyverno/validate/command.go
@@ -0,0 +1,64 @@
+package validate
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+
+	policyvalidate "github.com/nirmata/kyverno/pkg/engine/policy"
+
+	v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
+	"github.com/spf13/cobra"
+	"k8s.io/apimachinery/pkg/util/yaml"
+)
+
+func Command() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "validate",
+		Short:   "Validates kyverno policies",
+		Example: "kyverno validate /path/to/policy1 /path/to/policy2",
+		RunE: func(cmd *cobra.Command, policyPaths []string) error {
+			for _, policyPath := range policyPaths {
+				policy, err := getPolicy(policyPath)
+				if err != nil {
+					return err
+				}
+
+				err = policyvalidate.Validate(*policy)
+				if err != nil {
+					return err
+				}
+
+				fmt.Println("Policy " + policy.Name + " is valid")
+			}
+
+			return nil
+		},
+	}
+
+	return cmd
+}
+
+func getPolicy(path string) (*v1.ClusterPolicy, error) {
+	policy := &v1.ClusterPolicy{}
+
+	file, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, fmt.Errorf("failed to load file: %v", err)
+	}
+
+	policyBytes, err := yaml.ToJSON(file)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := json.Unmarshal(policyBytes, policy); err != nil {
+		return nil, fmt.Errorf("failed to decode policy %s, err: %v", policy.Name, err)
+	}
+
+	if policy.TypeMeta.Kind != "ClusterPolicy" {
+		return nil, fmt.Errorf("failed to parse policy")
+	}
+
+	return policy, nil
+}
diff --git a/pkg/kyverno/version/command.go b/pkg/kyverno/version/command.go
new file mode 100644
index 0000000000..25d1324f2a
--- /dev/null
+++ b/pkg/kyverno/version/command.go
@@ -0,0 +1,21 @@
+package version
+
+import (
+	"fmt"
+
+	"github.com/nirmata/kyverno/pkg/version"
+	"github.com/spf13/cobra"
+)
+
+func Command() *cobra.Command {
+	return &cobra.Command{
+		Use:   "version",
+		Short: "Shows current version of kyverno",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			fmt.Printf("Version: %s\n", version.BuildVersion)
+			fmt.Printf("Time: %s\n", version.BuildTime)
+			fmt.Printf("Git commit ID: %s\n", version.BuildHash)
+			return nil
+		},
+	}
+}
diff --git a/pkg/kyverno/version/version.go b/pkg/kyverno/version/version.go
deleted file mode 100644
index 8d1f5dfb75..0000000000
--- a/pkg/kyverno/version/version.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package version
-
-import (
-	"fmt"
-	"io"
-
-	"github.com/nirmata/kyverno/pkg/version"
-	"github.com/spf13/cobra"
-)
-
-// NewCmdVersion is a command to display the build version
-func NewCmdVersion(cmdOut io.Writer) *cobra.Command {
-
-	versionCmd := &cobra.Command{
-		Use:   "version",
-		Short: "",
-		Run: func(cmd *cobra.Command, args []string) {
-			showVersion()
-		},
-	}
-
-	return versionCmd
-}
-
-func showVersion() {
-	fmt.Printf("Version: %s\n", version.BuildVersion)
-	fmt.Printf("Time: %s\n", version.BuildTime)
-	fmt.Printf("Git commit ID: %s\n", version.BuildHash)
-}
diff --git a/pkg/webhookconfig/common.go b/pkg/webhookconfig/common.go
index d73fcafb13..00cfa79ef3 100644
--- a/pkg/webhookconfig/common.go
+++ b/pkg/webhookconfig/common.go
@@ -63,7 +63,6 @@ func (wrc *WebhookRegistrationClient) constructOwner() v1.OwnerReference {
 
 func generateDebugWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.Webhook {
 	sideEffect := admregapi.SideEffectClassNoneOnDryRun
-	failurePolicy := admregapi.Ignore
 	return admregapi.Webhook{
 		Name: name,
 		ClientConfig: admregapi.WebhookClientConfig{
@@ -89,13 +88,11 @@ func generateDebugWebhook(name, url string, caData []byte, validate bool, timeou
 		},
 		AdmissionReviewVersions: []string{"v1beta1"},
 		TimeoutSeconds:          &timeoutSeconds,
-		FailurePolicy:           &failurePolicy,
 	}
 }
 
 func generateWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.Webhook {
 	sideEffect := admregapi.SideEffectClassNoneOnDryRun
-	failurePolicy := admregapi.Ignore
 	return admregapi.Webhook{
 		Name: name,
 		ClientConfig: admregapi.WebhookClientConfig{
@@ -125,6 +122,5 @@ func generateWebhook(name, servicePath string, caData []byte, validation bool, t
 		},
 		AdmissionReviewVersions: []string{"v1beta1"},
 		TimeoutSeconds:          &timeoutSeconds,
-		FailurePolicy:           &failurePolicy,
 	}
 }
diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go
index f10289eced..7193661630 100644
--- a/pkg/webhooks/mutation.go
+++ b/pkg/webhooks/mutation.go
@@ -91,8 +91,6 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou
 		// gather patches
 		patches = append(patches, engineResponse.GetPatches()...)
 		glog.V(4).Infof("Mutation from policy %s has applied succesfully to %s %s/%s", policy.Name, request.Kind.Kind, resource.GetNamespace(), resource.GetName())
-
-		policyContext.NewResource = engineResponse.PatchedResource
 	}
 
 	// generate annotations
diff --git a/samples/best_practices/disallow_default_namespace.yaml b/samples/best_practices/disallow_default_namespace.yaml
index 0f579f4d49..64b1fe8844 100644
--- a/samples/best_practices/disallow_default_namespace.yaml
+++ b/samples/best_practices/disallow_default_namespace.yaml
@@ -3,7 +3,6 @@ kind: ClusterPolicy
 metadata:
   name: disallow-default-namespace
   annotations:
-    pod-policies.kyverno.io/autogen-controllers: none
     policies.kyverno.io/category: Workload Isolation
     policies.kyverno.io/description: Kubernetes namespaces are an optional feature 
       that provide a way to segment and isolate cluster resources across multiple