diff --git a/Makefile b/Makefile index 558ade3e27..9c1aa99e37 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ build: kyverno PWD := $(CURDIR) ################################## -# INIT CONTAINER +# INIT CONTAINER ################################## INITC_PATH := cmd/initContainer INITC_IMAGE := kyvernopre @@ -117,7 +117,7 @@ docker-build-cli-amd64: docker-push-cli: @docker buildx build --file $(PWD)/$(CLI_PATH)/Dockerfile --progress plane --push --platform linux/arm64,linux/amd64 --tag $(REPO)/$(KYVERNO_CLI_IMAGE):$(IMAGE_TAG) . --build-arg LD_FLAGS=$(LD_FLAGS) @docker buildx build --file $(PWD)/$(CLI_PATH)/Dockerfile --progress plane --push --platform linux/arm64,linux/amd64 --tag $(REPO)/$(KYVERNO_CLI_IMAGE):latest . --build-arg LD_FLAGS=$(LD_FLAGS) - + ################################## docker-publish-all: docker-publish-initContainer docker-publish-kyverno docker-publish-cli @@ -137,7 +137,7 @@ create-e2e-infrastruture: ################################## ################################## -# Testing & Code-Coverage +# Testing & Code-Coverage ################################## ## variables @@ -153,7 +153,7 @@ $(GO_ACC): go get -v github.com/ory/go-acc $(eval export PATH=$(GO_ACC):$(PATH)) # go test provides code coverage per packages only. -# go-acc merges the result for pks so that it be used by +# go-acc merges the result for pks so that it be used by # go tool cover for reporting # go get downloads and installs the binary @@ -171,7 +171,8 @@ code-cov-report: $(CODE_COVERAGE_FILE_TXT) # Test E2E test-e2e: $(eval export E2E="ok") - go test ./test/e2e/... -v + go test ./test/e2e/mutate -v + go test ./test/e2e/generate -v $(eval export E2E="") #Test TestCmd Policy @@ -183,9 +184,9 @@ run_testcmd_policy: godownloader: godownloader .goreleaser.yml --repo kyverno/kyverno -o ./scripts/install-cli.sh --source="raw" -# kustomize-crd will create install.yaml +# kustomize-crd will create install.yaml kustomize-crd: - # Create CRD for helm deployment Helm + # Create CRD for helm deployment Helm kustomize build ./definitions/crds > ./charts/kyverno/crds/crds.yaml # Generate install.yaml that have all resources for kyverno kustomize build ./definitions > ./definitions/install.yaml @@ -204,7 +205,7 @@ kyverno-crd: controller-gen report-crd: controller-gen $(CONTROLLER_GEN) crd paths=./pkg/api/policyreport/v1alpha1 output:dir=./definitions/crds -# install the right version of controller-gen +# install the right version of controller-gen install-controller-gen: @{ \ set -e ;\ diff --git a/test/e2e/generate/generate_test.go b/test/e2e/generate/generate_test.go index 0eb55d235a..041e3ab37c 100644 --- a/test/e2e/generate/generate_test.go +++ b/test/e2e/generate/generate_test.go @@ -3,26 +3,29 @@ package generate import ( "errors" "fmt" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "os" "testing" "time" + + "github.com/kyverno/kyverno/test/e2e" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" ) var ( // Cluster Polict GVR - clPolGVR = GetGVR("kyverno.io", "v1", "clusterpolicies") + clPolGVR = e2e.GetGVR("kyverno.io", "v1", "clusterpolicies") // Namespace GVR - nsGVR = GetGVR("", "v1", "namespaces") + nsGVR = e2e.GetGVR("", "v1", "namespaces") // ClusterRole GVR - crGVR = GetGVR("rbac.authorization.k8s.io", "v1", "clusterroles") + crGVR = e2e.GetGVR("rbac.authorization.k8s.io", "v1", "clusterroles") // ClusterRoleBinding GVR - crbGVR = GetGVR("rbac.authorization.k8s.io", "v1", "clusterrolebindings") + crbGVR = e2e.GetGVR("rbac.authorization.k8s.io", "v1", "clusterrolebindings") // Role GVR - rGVR = GetGVR("rbac.authorization.k8s.io", "v1", "roles") + rGVR = e2e.GetGVR("rbac.authorization.k8s.io", "v1", "roles") // RoleBinding GVR - rbGVR = GetGVR("rbac.authorization.k8s.io", "v1", "rolebindings") + rbGVR = e2e.GetGVR("rbac.authorization.k8s.io", "v1", "rolebindings") // ClusterPolicy Namespace clPolNS = "" @@ -37,7 +40,7 @@ func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) { t.Skip("Skipping E2E Test") } // Generate E2E Client ================== - e2eClient, err := NewE2EClient() + e2eClient, err := e2e.NewE2EClient() Expect(err).To(BeNil()) // ====================================== @@ -65,7 +68,7 @@ func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) { e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace) // Wait Till Deletion of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return nil @@ -100,7 +103,7 @@ func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) { Expect(err).NotTo(HaveOccurred()) // Wait Till Creation of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return err @@ -112,7 +115,7 @@ func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) { // ======== Verify ClusterRole Creation ===== By("Verifying ClusterRole") // Wait Till Creation of ClusterRole - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(crGVR, tests.ClusterRoleName) if err != nil { return err @@ -136,7 +139,7 @@ func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) { // Clear Namespace e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace) // Wait Till Deletion of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return nil @@ -154,7 +157,7 @@ func Test_Role_RoleBinding_Sets(t *testing.T) { t.Skip("Skipping E2E Test") } // Generate E2E Client ================== - e2eClient, err := NewE2EClient() + e2eClient, err := e2e.NewE2EClient() Expect(err).To(BeNil()) // ====================================== @@ -179,7 +182,7 @@ func Test_Role_RoleBinding_Sets(t *testing.T) { } // Wait Till Deletion of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return nil @@ -210,7 +213,7 @@ func Test_Role_RoleBinding_Sets(t *testing.T) { Expect(err).NotTo(HaveOccurred()) // Wait Till Creation of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return err @@ -222,7 +225,7 @@ func Test_Role_RoleBinding_Sets(t *testing.T) { // ======== Verify Role Creation ===== By(fmt.Sprintf("Verifying Role in the Namespace : %s", tests.ResourceNamespace)) // Wait Till Creation of Role - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetNamespacedResource(rGVR, tests.ResourceNamespace, tests.RoleName) if err != nil { return err @@ -255,7 +258,7 @@ func Test_Role_RoleBinding_Sets(t *testing.T) { // Clear Namespace e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace) // Wait Till Deletion of Namespace - GetWithRetry(time.Duration(1), 15, func() error { + e2e.GetWithRetry(time.Duration(1), 15, func() error { _, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace) if err != nil { return nil diff --git a/test/e2e/mutate/config.go b/test/e2e/mutate/config.go new file mode 100644 index 0000000000..26184bffbc --- /dev/null +++ b/test/e2e/mutate/config.go @@ -0,0 +1,18 @@ +package mutate + +// MutateTests is E2E Test Config for mutation +var MutateTests = []struct { + //TestName - Name of the Test + TestName string + // Data - The Yaml file of the ClusterPolicy + Data []byte +}{ + { + TestName: "test-mutate-with-context", + Data: configMapMutationYaml, + }, + { + TestName: "test-mutate-with-logic-in-context", + Data: configMapMutationWithContextLogicYaml, + }, +} diff --git a/test/e2e/mutate/mutate_test.go b/test/e2e/mutate/mutate_test.go new file mode 100644 index 0000000000..5b95edc04d --- /dev/null +++ b/test/e2e/mutate/mutate_test.go @@ -0,0 +1,109 @@ +package mutate + +import ( + "errors" + "fmt" + "os" + "testing" + "time" + + "github.com/kyverno/kyverno/test/e2e" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var ( + // Cluster Polict GVR + clPolGVR = e2e.GetGVR("kyverno.io", "v1", "clusterpolicies") + // Namespace GVR + nsGVR = e2e.GetGVR("", "v1", "namespaces") + // ConfigMap GVR + cmGVR = e2e.GetGVR("", "v1", "configmaps") + + // ClusterPolicy Namespace + clPolNS = "" + // Namespace Name + // Hardcoded in YAML Definition + nspace = "test-mutate" +) + +func Test_Mutate_Sets(t *testing.T) { + RegisterTestingT(t) + if os.Getenv("E2E") == "" { + t.Skip("Skipping E2E Test") + } + // Generate E2E Client + e2eClient, err := e2e.NewE2EClient() + Expect(err).To(BeNil()) + + for _, tests := range MutateTests { + By(fmt.Sprintf("Test to mutate objects : %s", tests.TestName)) + + // Clean up Resources + By(fmt.Sprintf("Cleaning Cluster Policies")) + e2eClient.CleanClusterPolicies(clPolGVR) + // Clear Namespace + By(fmt.Sprintf("Deleting Namespace : %s", nspace)) + e2eClient.DeleteClusteredResource(nsGVR, nspace) + + // Wait Till Deletion of Namespace + e2e.GetWithRetry(time.Duration(1), 15, func() error { + _, err := e2eClient.GetClusteredResource(nsGVR, nspace) + if err != nil { + return nil + } + return errors.New("Deleting Namespace") + }) + + // Create Namespace + By(fmt.Sprintf("Creating Namespace %s", clPolNS)) + _, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceYaml) + Expect(err).NotTo(HaveOccurred()) + + // Create source CM + By(fmt.Sprintf("\nCreating source ConfigMap in %s", nspace)) + _, err = e2eClient.CreateNamespacedResourceYaml(cmGVR, nspace, sourceConfigMapYaml) + Expect(err).NotTo(HaveOccurred()) + + // Create CM Policy + By(fmt.Sprintf("\nCreating Mutate ConfigMap Policy in %s", clPolNS)) + _, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, clPolNS, tests.Data) + Expect(err).NotTo(HaveOccurred()) + + // Create target CM + By(fmt.Sprintf("\nCreating target ConfigMap in %s", nspace)) + _, err = e2eClient.CreateNamespacedResourceYaml(cmGVR, nspace, targetConfigMapYaml) + Expect(err).NotTo(HaveOccurred()) + + // Verify created ConfigMap + By(fmt.Sprintf("Verifying ConfigMap in the Namespace : %s", nspace)) + // Wait Till Creation of ConfigMap + e2e.GetWithRetry(time.Duration(1), 15, func() error { + _, err := e2eClient.GetNamespacedResource(cmGVR, nspace, "target") + if err != nil { + return err + } + return nil + }) + cmRes, err := e2eClient.GetNamespacedResource(cmGVR, nspace, "target") + Expect(err).NotTo(HaveOccurred()) + Expect(cmRes.GetLabels()["kyverno.key/copy-me"]).To(Equal("sample-value")) + + //CleanUp Resources + e2eClient.CleanClusterPolicies(clPolGVR) + + // Clear Namespace + e2eClient.DeleteClusteredResource(nsGVR, nspace) + // Wait Till Deletion of Namespace + e2e.GetWithRetry(time.Duration(1), 15, func() error { + _, err := e2eClient.GetClusteredResource(nsGVR, nspace) + if err != nil { + return nil + } + return errors.New("Deleting Namespace") + }) + + By(fmt.Sprintf("Test %s Completed \n\n\n", tests.TestName)) + } + +} diff --git a/test/e2e/mutate/resources.go b/test/e2e/mutate/resources.go new file mode 100644 index 0000000000..e49d66ae7f --- /dev/null +++ b/test/e2e/mutate/resources.go @@ -0,0 +1,84 @@ +package mutate + +// Namespace Description +var namespaceYaml = []byte(` +apiVersion: v1 +kind: Namespace +metadata: + name: test-mutate +`) + +// Cluster Policy to copy the copy me label from one configmap to the target +var configMapMutationYaml = []byte(` +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: "mutate-policy" +spec: + rules: + - name: "gen-role" + match: + resources: + kinds: + - ConfigMap + context: + - name: labelValue + apiCall: + urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}/configmaps" + jmesPath: "items[*]" + mutate: + patchStrategicMerge: + metadata: + labels: + +(kyverno.key/copy-me): "{{ labelValue[?metadata.name == 'source'].metadata.labels.\"kyverno.key/copy-me\" | [0] }}" +`) + +var configMapMutationWithContextLogicYaml = []byte(` +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: "mutate-policy" +spec: + rules: + - name: "gen-role" + match: + resources: + kinds: + - ConfigMap + context: + - name: labelValue + apiCall: + urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}/configmaps" + jmesPath: "items[?metadata.name == 'source'].metadata.labels.\"kyverno.key/copy-me\" | [0]" + mutate: + patchStrategicMerge: + metadata: + labels: + +(kyverno.key/copy-me): "{{ labelValue }}" +`) + +// Source ConfigMap from which data is taken to copy +var sourceConfigMapYaml = []byte(` +apiVersion: v1 +kind: ConfigMap +metadata: + name: source + namespace: test-mutate + labels: + kyverno.key/copy-me: sample-value +data: + data.yaml: | + some: data +`) + +// Target ConfigMap which is mutated +var targetConfigMapYaml = []byte(` +apiVersion: v1 +kind: ConfigMap +metadata: + name: target + namespace: test-mutate +data: + data.yaml: | + some: data +`) diff --git a/test/e2e/generate/utils.go b/test/e2e/utils.go similarity index 99% rename from test/e2e/generate/utils.go rename to test/e2e/utils.go index 9407a68827..b832756a80 100644 --- a/test/e2e/generate/utils.go +++ b/test/e2e/utils.go @@ -1,4 +1,4 @@ -package generate +package e2e import ( "context"