1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00

add e2e tests for mutate existing policies (#3703)

Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
shuting 2022-04-28 03:44:52 +08:00 committed by GitHub
parent ab5171cee5
commit b740e84f06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 648 additions and 1 deletions

View file

@ -11,6 +11,9 @@ rules:
- clusterroles
- rolebindings
- clusterrolebindings
- secrets
- configmaps
- deployments
verbs:
- create
- delete

View file

@ -171,3 +171,104 @@ var ingressTests = struct {
},
},
}
type mutateExistingOperation string
const (
createTrigger mutateExistingOperation = "createTrigger"
deleteTrigger mutateExistingOperation = "deleteTrigger"
createPolicy mutateExistingOperation = "createPolicy"
)
// Note: sometimes deleting namespaces takes time.
// Using different names for namespaces prevents collisions.
var mutateExistingTests = []struct {
// TestDescription - Description of the Test
TestDescription string
// Operation describes how to trigger the policy
Operation mutateExistingOperation
// PolicyName - Name of the Policy
PolicyName string
// PolicyRaw - The Yaml file of the ClusterPolicy
PolicyRaw []byte
// TriggerName - Name of the Trigger Resource
TriggerName string
// TriggerNamespace - Namespace of the Trigger Resource
TriggerNamespace string
// TriggerGVR - GVR of the Trigger Resource
TriggerGVR schema.GroupVersionResource
// TriggerRaw - The Yaml file of the Trigger Resource
TriggerRaw []byte
// TargetName - Name of the Target Resource
TargetName string
// TargetNamespace - Namespace of the Target Resource
TargetNamespace string
// TargetGVR - GVR of the Target Resource
TargetGVR schema.GroupVersionResource
// TargetRaw - The Yaml file of the Target ClusterPolicy
TargetRaw []byte
// ExpectedTargetRaw - The Yaml file that contains validate pattern for the expected result
// This is not the final result. It is just used to validate the result from the engine.
ExpectedTargetRaw []byte
}{
{
TestDescription: "mutate existing on resource creation",
Operation: createTrigger,
PolicyName: "test-post-mutation-create-trigger",
PolicyRaw: policyCreateTrigger,
TriggerName: "dictionary-1",
TriggerNamespace: "staging-1",
TriggerGVR: configmGVR,
TriggerRaw: triggerCreateTrigger,
TargetName: "test-secret-1",
TargetNamespace: "staging-1",
TargetGVR: secretGVR,
TargetRaw: targetCreateTrigger,
ExpectedTargetRaw: expectedTargetCreateTrigger,
},
{
TestDescription: "mutate existing on resource deletion",
Operation: deleteTrigger,
PolicyName: "test-post-mutation-delete-trigger",
PolicyRaw: policyDeleteTrigger,
TriggerName: "dictionary-2",
TriggerNamespace: "staging-2",
TriggerGVR: configmGVR,
TriggerRaw: triggerDeleteTrigger,
TargetName: "test-secret-2",
TargetNamespace: "staging-2",
TargetGVR: secretGVR,
TargetRaw: targetDeleteTrigger,
ExpectedTargetRaw: expectedTargetDeleteTrigger,
},
{
TestDescription: "mutate existing on policy creation",
Operation: createPolicy,
PolicyName: "test-post-mutation-create-policy",
PolicyRaw: policyCreatePolicy,
TriggerName: "dictionary-3",
TriggerNamespace: "staging-3",
TriggerGVR: configmGVR,
TriggerRaw: triggerCreatePolicy,
TargetName: "test-secret-3",
TargetNamespace: "staging-3",
TargetGVR: secretGVR,
TargetRaw: targetCreatePolicy,
ExpectedTargetRaw: expectedTargetCreatePolicy,
},
{
TestDescription: "mutate existing (patchesJson6902) on resource creation",
Operation: createTrigger,
PolicyName: "test-post-mutation-json-patch-create-trigger",
PolicyRaw: policyCreateTriggerJsonPatch,
TriggerName: "dictionary-4",
TriggerNamespace: "staging-4",
TriggerGVR: configmGVR,
TriggerRaw: triggerCreateTriggerJsonPatch,
TargetName: "test-secret-4",
TargetNamespace: "staging-4",
TargetGVR: secretGVR,
TargetRaw: targetCreateTriggerJsonPatch,
ExpectedTargetRaw: expectedCreateTriggerJsonPatch,
},
}

View file

@ -164,7 +164,7 @@ func Test_Mutate(t *testing.T) {
})
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Creating Namespace: %s...", policyNamespace))
By(fmt.Sprintf("Creating Namespace: %s...", test.ResourceNamespace))
_, err = e2eClient.CreateClusteredResourceYaml(namespaceGVR, newNamespaceYaml(test.ResourceNamespace))
Expect(err).NotTo(HaveOccurred())
@ -315,6 +315,270 @@ func Test_Mutate_Ingress(t *testing.T) {
}
}
func Test_Mutate_Existing(t *testing.T) {
RegisterTestingT(t)
if os.Getenv("E2E") == "" {
t.Skip("Skipping E2E Test")
}
e2eClient, err := e2e.NewE2EClient()
Expect(err).To(BeNil())
for _, test := range mutateExistingTests {
By(fmt.Sprintf("\nStart Mutate Existing Tests: %s", test.TestDescription))
By("======Cleaning up resources======")
By("Deleting Cluster Policies...")
e2eClient.CleanClusterPolicies(policyGVR)
By(fmt.Sprintf("Deleting Trigger Resource %v %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
e2eClient.DeleteNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
By(fmt.Sprintf("Deleting Trigger Namespace: %s...", test.TriggerNamespace))
e2eClient.DeleteClusteredResource(namespaceGVR, test.TriggerNamespace)
By("Wait Till Deletion of Trigger Namespace...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(namespaceGVR, test.TriggerNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Deleting Target Resource %v %s/%s...", test.TargetGVR, test.TargetNamespace, test.TargetName))
e2eClient.DeleteNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
By(fmt.Sprintf("Deleting Target Namespace: %s...", test.TargetNamespace))
e2eClient.DeleteClusteredResource(namespaceGVR, test.TargetNamespace)
By("Wait Till Deletion of Target Namespace...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(namespaceGVR, test.TargetNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
Expect(err).NotTo(HaveOccurred())
By("======Done cleaning up resources======")
By(fmt.Sprintf("Creating target Namespace: %s...", test.TargetNamespace))
_, err = e2eClient.CreateClusteredResourceYaml(namespaceGVR, newNamespaceYaml(test.TargetNamespace))
Expect(err).NotTo(HaveOccurred())
By("Wait Till Creation of Namespace...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(namespaceGVR, test.TargetNamespace)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Creating Target Resource %v, %s/%s...", test.TargetGVR, test.TargetNamespace, test.TargetName))
_, err = e2eClient.CreateNamespacedResourceYaml(test.TargetGVR, test.TargetNamespace, test.TargetName, test.TargetRaw)
Expect(err).NotTo(HaveOccurred())
By("Checking that resource is created...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
switch test.Operation {
case createTrigger:
By("Operation: createTrigger\n Creating Policy...")
_, err = e2eClient.CreateNamespacedResourceYaml(policyGVR, policyNamespace, test.PolicyName, test.PolicyRaw)
Expect(err).NotTo(HaveOccurred())
err = commonE2E.PolicyCreated(test.PolicyName)
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Creating Trigger Resource %v, %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
_, err = e2eClient.CreateNamespacedResourceYaml(test.TriggerGVR, test.TriggerNamespace, test.TriggerName, test.TriggerRaw)
Expect(err).NotTo(HaveOccurred())
By("Checking that resource is created...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
// wait for UR to be completed
time.Sleep(3 * time.Second)
res, err := e2eClient.GetNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
Expect(err).NotTo(HaveOccurred())
actualJSON, err := json.Marshal(res)
Expect(err).NotTo(HaveOccurred())
var actual interface{}
err = json.Unmarshal(actualJSON, &actual)
Expect(err).NotTo(HaveOccurred())
expected, err := rawYAMLToJSONInterface(test.ExpectedTargetRaw)
Expect(err).NotTo(HaveOccurred())
By("Validating created resource with the expected pattern...")
err = validate.MatchPattern(log.Log, actual, expected)
Expect(err).NotTo(HaveOccurred())
case deleteTrigger:
By(fmt.Sprintf("Operation: deleteTrigger\n Creating Trigger Resource %v, %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
_, err = e2eClient.CreateNamespacedResourceYaml(test.TriggerGVR, test.TriggerNamespace, test.TriggerName, test.TriggerRaw)
Expect(err).NotTo(HaveOccurred())
By("Checking that resource is created...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
By("Creating Policy...")
_, err = e2eClient.CreateNamespacedResourceYaml(policyGVR, policyNamespace, test.PolicyName, test.PolicyRaw)
Expect(err).NotTo(HaveOccurred())
err = commonE2E.PolicyCreated(test.PolicyName)
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Deleting Trigger Resource to Trigger Policy %v %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
e2eClient.DeleteNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
// wait for UR to be completed
time.Sleep(3 * time.Second)
res, err := e2eClient.GetNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
Expect(err).NotTo(HaveOccurred())
actualJSON, err := json.Marshal(res)
Expect(err).NotTo(HaveOccurred())
var actual interface{}
err = json.Unmarshal(actualJSON, &actual)
Expect(err).NotTo(HaveOccurred())
expected, err := rawYAMLToJSONInterface(test.ExpectedTargetRaw)
Expect(err).NotTo(HaveOccurred())
By("Validating created resource with the expected pattern...")
err = validate.MatchPattern(log.Log, actual, expected)
Expect(err).NotTo(HaveOccurred())
case createPolicy:
By(fmt.Sprintf("Operation: createPolicy\n Creating Trigger Resource %v, %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
_, err = e2eClient.CreateNamespacedResourceYaml(test.TriggerGVR, test.TriggerNamespace, test.TriggerName, test.TriggerRaw)
Expect(err).NotTo(HaveOccurred())
By("Checking that resource is created...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
By("Creating Policy...")
_, err = e2eClient.CreateNamespacedResourceYaml(policyGVR, policyNamespace, test.PolicyName, test.PolicyRaw)
Expect(err).NotTo(HaveOccurred())
err = commonE2E.PolicyCreated(test.PolicyName)
Expect(err).NotTo(HaveOccurred())
// wait for UR to be completed
time.Sleep(3 * time.Second)
res, err := e2eClient.GetNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
Expect(err).NotTo(HaveOccurred())
actualJSON, err := json.Marshal(res)
Expect(err).NotTo(HaveOccurred())
var actual interface{}
err = json.Unmarshal(actualJSON, &actual)
Expect(err).NotTo(HaveOccurred())
expected, err := rawYAMLToJSONInterface(test.ExpectedTargetRaw)
Expect(err).NotTo(HaveOccurred())
By("Validating created resource with the expected pattern...")
err = validate.MatchPattern(log.Log, actual, expected)
Expect(err).NotTo(HaveOccurred())
}
By("Deleting Cluster Policies...")
e2eClient.CleanClusterPolicies(policyGVR)
By(fmt.Sprintf("Deleting Trigger Resource %v %s/%s...", test.TriggerGVR, test.TriggerNamespace, test.TriggerName))
e2eClient.DeleteNamespacedResource(test.TriggerGVR, test.TriggerNamespace, test.TriggerName)
By(fmt.Sprintf("Deleting Trigger Namespace: %s...", test.TriggerNamespace))
e2eClient.DeleteClusteredResource(namespaceGVR, test.TriggerNamespace)
By("Wait Till Deletion of Trigger Namespace...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(namespaceGVR, test.TriggerNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
// Do not fail if waiting fails. Sometimes namespace needs time to be deleted.
if err != nil {
By(err.Error())
}
By(fmt.Sprintf("Deleting Target Resource %v %s/%s...", test.TargetGVR, test.TargetNamespace, test.TargetName))
e2eClient.DeleteNamespacedResource(test.TargetGVR, test.TargetNamespace, test.TargetName)
By(fmt.Sprintf("Deleting Target Namespace: %s...", test.TargetNamespace))
e2eClient.DeleteClusteredResource(namespaceGVR, test.TargetNamespace)
By("Wait Till Deletion of Target Namespace...")
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(namespaceGVR, test.TargetNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
// Do not fail if waiting fails. Sometimes namespace needs time to be deleted.
if err != nil {
By(err.Error())
}
By("Done")
}
}
func rawYAMLToJSONInterface(y []byte) (interface{}, error) {
var temp, result interface{}
var err error

View file

@ -8,6 +8,8 @@ import (
var podGVR = e2e.GetGVR("", "v1", "pods")
var deploymentGVR = e2e.GetGVR("apps", "v1", "deployments")
var configmGVR = e2e.GetGVR("", "v1", "configmaps")
var secretGVR = e2e.GetGVR("", "v1", "secrets")
func newNamespaceYaml(name string) []byte {
ns := fmt.Sprintf(`
@ -668,3 +670,280 @@ spec:
type: DirectoryOrCreate
name: test-volume
`)
var policyCreateTrigger = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "test-post-mutation-create-trigger"
spec:
rules:
- name: "mutate-deploy-on-configmap-create"
match:
any:
- resources:
kinds:
- ConfigMap
names:
- dictionary-1
namespaces:
- staging-1
mutate:
targets:
- apiVersion: v1
kind: Secret
name: test-secret-1
namespace: "{{ request.object.metadata.namespace }}"
patchStrategicMerge:
metadata:
labels:
foo: "{{ request.object.metadata.name }}"
`)
var triggerCreateTrigger = []byte(`
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
test: createTrigger
name: dictionary-1
namespace: staging-1
`)
var targetCreateTrigger = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-1
namespace: staging-1
labels:
test: createTrigger
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var expectedTargetCreateTrigger = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-1
namespace: staging-1
labels:
test: createTrigger
foo: dictionary-1
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var policyDeleteTrigger = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "test-post-mutation-delete-trigger"
spec:
rules:
- name: "mutate-deploy-on-configmap-delete"
match:
any:
- resources:
kinds:
- ConfigMap
names:
- dictionary-2
namespaces:
- staging-2
preconditions:
any:
- key: "{{ request.operation }}"
operator: Equals
value: DELETE
mutate:
targets:
- apiVersion: v1
kind: Secret
name: test-secret-2
namespace: "{{ request.object.metadata.namespace }}"
patchStrategicMerge:
metadata:
labels:
foo: "{{ request.object.metadata.name }}"
`)
var triggerDeleteTrigger = []byte(`
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
test: deleteTrigger
name: dictionary-2
namespace: staging-2
`)
var targetDeleteTrigger = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-2
namespace: staging-2
labels:
test: deleteTrigger
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var expectedTargetDeleteTrigger = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-2
namespace: staging-2
labels:
test: deleteTrigger
foo: dictionary-2
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var policyCreatePolicy = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "test-post-mutation-create-policy"
spec:
rules:
- name: "mutate-deploy-on-policy-create"
match:
any:
- resources:
kinds:
- ConfigMap
names:
- dictionary-3
namespaces:
- staging-3
mutate:
targets:
- apiVersion: v1
kind: Secret
name: test-secret-3
namespace: "{{ request.object.metadata.namespace }}"
patchStrategicMerge:
metadata:
labels:
foo: "{{ request.object.metadata.name }}"
`)
var triggerCreatePolicy = []byte(`
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
test: createPolicy
name: dictionary-3
namespace: staging-3
`)
var targetCreatePolicy = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-3
namespace: staging-3
labels:
test: createPolicy
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var expectedTargetCreatePolicy = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-3
namespace: staging-3
labels:
test: createPolicy
foo: dictionary-3
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var policyCreateTriggerJsonPatch = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "test-post-mutation"
spec:
rules:
- name: "mutate-deploy-on-configmap-update"
match:
any:
- resources:
kinds:
- ConfigMap
names:
- dictionary-4
namespaces:
- staging-4
mutate:
targets:
- apiVersion: v1
kind: Secret
name: test-secret-4
namespace: "{{ request.object.metadata.namespace }}"
patchesJson6902: |-
- op: add
path: "/metadata/labels/env"
value: "{{ request.object.metadata.namespace }}"
`)
var triggerCreateTriggerJsonPatch = []byte(`
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
test: createTrigger
name: dictionary-4
namespace: staging-4
`)
var targetCreateTriggerJsonPatch = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-4
namespace: staging-4
labels:
test: createTrigger
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)
var expectedCreateTriggerJsonPatch = []byte(`
apiVersion: v1
kind: Secret
metadata:
name: test-secret-4
namespace: staging-4
labels:
test: createTrigger
env: staging-4
type: Opaque
data:
value: Z29vZGJ5ZQ==
`)