mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
test: add test case for duplicate check and report unused resources (#6653)
* add test case Signed-off-by: bakito <github@bakito.ch> * also print obsolete resources Signed-off-by: bakito <github@bakito.ch> --------- Signed-off-by: bakito <github@bakito.ch> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
893c22b96b
commit
cdf79daa44
9 changed files with 292 additions and 12 deletions
|
@ -230,7 +230,7 @@ type testFilter struct {
|
||||||
enabled bool
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var ftable = []Table{}
|
var ftable []Table
|
||||||
|
|
||||||
func testCommandExecute(dirPath []string, fileName string, gitBranch string, testCase string, failOnly bool, removeColor bool) (rc *resultCounts, err error) {
|
func testCommandExecute(dirPath []string, fileName string, gitBranch string, testCase string, failOnly bool, removeColor bool) (rc *resultCounts, err error) {
|
||||||
var errors []error
|
var errors []error
|
||||||
|
@ -756,7 +756,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\nExecuting %s...", values.Name)
|
fmt.Printf("\nExecuting %s...\n", values.Name)
|
||||||
valuesFile := values.Variables
|
valuesFile := values.Variables
|
||||||
userInfoFile := values.UserInfo
|
userInfoFile := values.UserInfo
|
||||||
|
|
||||||
|
@ -802,7 +802,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredPolicies := []kyvernov1.PolicyInterface{}
|
var filteredPolicies []kyvernov1.PolicyInterface
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
for _, res := range values.Results {
|
for _, res := range values.Results {
|
||||||
if p.GetName() == res.Policy {
|
if p.GetName() == res.Policy {
|
||||||
|
@ -814,7 +814,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
||||||
|
|
||||||
ruleToCloneSourceResource := map[string]string{}
|
ruleToCloneSourceResource := map[string]string{}
|
||||||
for _, p := range filteredPolicies {
|
for _, p := range filteredPolicies {
|
||||||
filteredRules := []kyvernov1.Rule{}
|
var filteredRules []kyvernov1.Rule
|
||||||
|
|
||||||
for _, rule := range autogen.ComputeRules(p) {
|
for _, rule := range autogen.ComputeRules(p) {
|
||||||
for _, res := range values.Results {
|
for _, res := range values.Results {
|
||||||
|
@ -869,7 +869,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(policies) > 0 && len(checkableResources) > 0 {
|
if len(policies) > 0 && len(checkableResources) > 0 {
|
||||||
fmt.Printf("\napplying %s to %s... \n", msgPolicies, msgResources)
|
fmt.Printf("applying %s to %s... \n", msgPolicies, msgResources)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
|
@ -929,6 +929,14 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
|
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
|
||||||
|
res, _, _ := selectResourcesForCheckInternal(resources, values)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectResourcesForCheckInternal internal method to test duplicates and unused
|
||||||
|
func selectResourcesForCheckInternal(resources []*unstructured.Unstructured, values *api.Test) ([]*unstructured.Unstructured, int, int) {
|
||||||
|
var duplicates int
|
||||||
|
var unused int
|
||||||
uniqResources := make(map[string]*unstructured.Unstructured)
|
uniqResources := make(map[string]*unstructured.Unstructured)
|
||||||
|
|
||||||
for i := range resources {
|
for i := range resources {
|
||||||
|
@ -936,6 +944,7 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
||||||
key := fmt.Sprintf("%s/%s/%s", r.GetKind(), r.GetName(), r.GetNamespace())
|
key := fmt.Sprintf("%s/%s/%s", r.GetKind(), r.GetName(), r.GetNamespace())
|
||||||
if _, ok := uniqResources[key]; ok {
|
if _, ok := uniqResources[key]; ok {
|
||||||
fmt.Println("skipping duplicate resource, resource :", r)
|
fmt.Println("skipping duplicate resource, resource :", r)
|
||||||
|
duplicates++
|
||||||
} else {
|
} else {
|
||||||
uniqResources[key] = r
|
uniqResources[key] = r
|
||||||
}
|
}
|
||||||
|
@ -945,14 +954,16 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
||||||
for key := range uniqResources {
|
for key := range uniqResources {
|
||||||
r := uniqResources[key]
|
r := uniqResources[key]
|
||||||
for _, res := range values.Results {
|
for _, res := range values.Results {
|
||||||
for _, testr := range res.Resources {
|
if res.Kind == r.GetKind() {
|
||||||
if r.GetName() == testr {
|
for _, testr := range res.Resources {
|
||||||
|
if r.GetName() == testr {
|
||||||
|
selectedResources[key] = r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.GetName() == res.Resource {
|
||||||
selectedResources[key] = r
|
selectedResources[key] = r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.GetName() == res.Resource {
|
|
||||||
selectedResources[key] = r
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,13 +971,18 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
||||||
|
|
||||||
for key := range selectedResources {
|
for key := range selectedResources {
|
||||||
checkableResources = append(checkableResources, selectedResources[key])
|
checkableResources = append(checkableResources, selectedResources[key])
|
||||||
|
delete(uniqResources, key)
|
||||||
}
|
}
|
||||||
return checkableResources
|
for _, r := range uniqResources {
|
||||||
|
fmt.Println("skipping unused resource, resource :", r)
|
||||||
|
unused++
|
||||||
|
}
|
||||||
|
return checkableResources, duplicates, unused
|
||||||
}
|
}
|
||||||
|
|
||||||
func printTestResult(resps map[string]policyreportv1alpha2.PolicyReportResult, testResults []api.TestResults, rc *resultCounts, failOnly, removeColor bool) error {
|
func printTestResult(resps map[string]policyreportv1alpha2.PolicyReportResult, testResults []api.TestResults, rc *resultCounts, failOnly, removeColor bool) error {
|
||||||
printer := newTablePrinter(removeColor)
|
printer := newTablePrinter(removeColor)
|
||||||
table := []Table{}
|
var table []Table
|
||||||
|
|
||||||
var countDeprecatedResource int
|
var countDeprecatedResource int
|
||||||
testCount := 1
|
testCount := 1
|
||||||
|
|
92
cmd/cli/kubectl-kyverno/test/test_command_test.go
Normal file
92
cmd/cli/kubectl-kyverno/test/test_command_test.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
|
||||||
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_selectResourcesForCheck(t *testing.T) {
|
||||||
|
|
||||||
|
type TestCase struct {
|
||||||
|
testFile string
|
||||||
|
expectedResources int
|
||||||
|
expectedDuplicates int
|
||||||
|
expectedUnused int
|
||||||
|
}
|
||||||
|
baseTestDir := "../../../../test/cli/test-unit/selectResourcesForCheck/"
|
||||||
|
testcases := []*TestCase{
|
||||||
|
{
|
||||||
|
|
||||||
|
testFile: "kyverno-test-duplicated-with-resource.yaml",
|
||||||
|
expectedResources: 3,
|
||||||
|
expectedDuplicates: 1,
|
||||||
|
expectedUnused: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testFile: "kyverno-test-duplicated-with-resources.yaml",
|
||||||
|
expectedResources: 3,
|
||||||
|
expectedDuplicates: 1,
|
||||||
|
expectedUnused: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testFile: "kyverno-test-uniq-with-resource.yaml",
|
||||||
|
expectedResources: 3,
|
||||||
|
expectedDuplicates: 0,
|
||||||
|
expectedUnused: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testFile: "kyverno-test-uniq-with-resources.yaml",
|
||||||
|
expectedResources: 3,
|
||||||
|
expectedDuplicates: 0,
|
||||||
|
expectedUnused: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fs := memfs.New()
|
||||||
|
for _, tc := range testcases {
|
||||||
|
|
||||||
|
// read test spec
|
||||||
|
values := &api.Test{}
|
||||||
|
testBytes, err := os.ReadFile(filepath.Join(baseTestDir, tc.testFile))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
err = yaml.Unmarshal(testBytes, values)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// read policies
|
||||||
|
policies, err := common.GetPoliciesFromPaths(
|
||||||
|
fs,
|
||||||
|
[]string{filepath.Join(baseTestDir, values.Policies[0])},
|
||||||
|
false,
|
||||||
|
filepath.Join(baseTestDir, values.Resources[0]),
|
||||||
|
)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// read resources
|
||||||
|
resources, err := common.GetResourceAccordingToResourcePath(
|
||||||
|
fs,
|
||||||
|
[]string{filepath.Join(baseTestDir, values.Resources[0])},
|
||||||
|
false,
|
||||||
|
policies,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
filepath.Join(baseTestDir, values.Policies[0]),
|
||||||
|
)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
selected, duplicates, unused := selectResourcesForCheckInternal(resources, values)
|
||||||
|
assert.Equal(t, len(selected), tc.expectedResources,
|
||||||
|
"Did not get the expected number of resources for test %s", tc.testFile)
|
||||||
|
assert.Equal(t, duplicates, tc.expectedDuplicates,
|
||||||
|
"Did not get the expected number of duplicates for test %s", tc.testFile)
|
||||||
|
assert.Equal(t, unused, tc.expectedUnused,
|
||||||
|
"Did not get the expected number of unused resources for test %s", tc.testFile)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: just a dummy policy
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- name: dummy-rule-1
|
||||||
|
- name: dummy-rule-2
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: dummy-policy
|
||||||
|
policies:
|
||||||
|
- dummy-policy.yaml
|
||||||
|
resources:
|
||||||
|
- resource-duplicates.yaml
|
||||||
|
|
||||||
|
results:
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resource: myapp-pod1
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resource: myapp-pod2
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
|
@ -0,0 +1,19 @@
|
||||||
|
name: dummy-policy
|
||||||
|
policies:
|
||||||
|
- dummy-policy.yaml
|
||||||
|
resources:
|
||||||
|
- resource-duplicates.yaml
|
||||||
|
|
||||||
|
results:
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod1
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod2
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
|
@ -0,0 +1,19 @@
|
||||||
|
name: dummy-policy
|
||||||
|
policies:
|
||||||
|
- dummy-policy.yaml
|
||||||
|
resources:
|
||||||
|
- resource-uniq.yaml
|
||||||
|
|
||||||
|
results:
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod1
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod2
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
|
@ -0,0 +1,19 @@
|
||||||
|
name: dummy-policy
|
||||||
|
policies:
|
||||||
|
- dummy-policy.yaml
|
||||||
|
resources:
|
||||||
|
- resource-uniq.yaml
|
||||||
|
|
||||||
|
results:
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod1
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
||||||
|
- policy: dummy-policy
|
||||||
|
rule: require-image-tag
|
||||||
|
resources:
|
||||||
|
- myapp-pod2
|
||||||
|
kind: Pod
|
||||||
|
result: pass
|
|
@ -0,0 +1,49 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod1
|
||||||
|
namespace: foo
|
||||||
|
|
||||||
|
---
|
||||||
|
# duplicate pod
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod1
|
||||||
|
namespace: foo
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2
|
||||||
|
namespace: foo
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2
|
||||||
|
namespace: bar
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod3
|
||||||
|
namespace: bar
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2 # reuse the name of the pod to check duplicate check
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: myns
|
|
@ -0,0 +1,41 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod1
|
||||||
|
namespace: foo
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2
|
||||||
|
namespace: foo
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2
|
||||||
|
namespace: bar
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod3
|
||||||
|
namespace: bar
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: myapp-pod2 # reuse the name of the pod to check duplicate check
|
||||||
|
|
||||||
|
---
|
||||||
|
# will not be used
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: myns
|
Loading…
Add table
Reference in a new issue