From cb364904b6897a476417cc4f735b79b04f627556 Mon Sep 17 00:00:00 2001 From: Trey Dockendorf Date: Mon, 3 May 2021 08:20:22 -0400 Subject: [PATCH] Improved error handling for test command Signed-off-by: Trey Dockendorf --- Makefile | 1 + pkg/kyverno/test/command.go | 52 ++++++++++++++++-------------------- test/cli/test/policy.yaml | 35 ++++++++++++++++++++++++ test/cli/test/resources.yaml | 21 +++++++++++++++ test/cli/test/test.yaml | 14 ++++++++++ 5 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 test/cli/test/policy.yaml create mode 100644 test/cli/test/resources.yaml create mode 100644 test/cli/test/test.yaml diff --git a/Makefile b/Makefile index 9c1aa99e37..e834cc6116 100644 --- a/Makefile +++ b/Makefile @@ -179,6 +179,7 @@ test-e2e: run_testcmd_policy: go build -o kyvernoctl cmd/cli/kubectl-kyverno/main.go ./kyvernoctl test https://github.com/kyverno/policies/main + ./kyvernoctl test ./test/cli/test # godownloader create downloading script for kyverno-cli godownloader: diff --git a/pkg/kyverno/test/command.go b/pkg/kyverno/test/command.go index fa519d9e81..28346aaa37 100644 --- a/pkg/kyverno/test/command.go +++ b/pkg/kyverno/test/command.go @@ -145,83 +145,77 @@ func testCommandExecute(dirPath []string, valuesFile string, fileName string) (r sort.Strings(policyYamls) for _, yamlFilePath := range policyYamls { file, err := fs.Open(yamlFilePath) + if err != nil { + errors = append(errors, sanitizederror.NewWithError("Error: failed to open file", err)) + continue + } if strings.Contains(file.Name(), fileName) { testYamlCount++ policyresoucePath := strings.Trim(yamlFilePath, fileName) bytes, err := ioutil.ReadAll(file) if err != nil { - sanitizederror.NewWithError("Error: failed to read file", err) + errors = append(errors, sanitizederror.NewWithError("Error: failed to read file", err)) continue } policyBytes, err := yaml.ToJSON(bytes) if err != nil { - sanitizederror.NewWithError("failed to convert to JSON", err) + errors = append(errors, sanitizederror.NewWithError("failed to convert to JSON", err)) continue } if err := applyPoliciesFromPath(fs, policyBytes, valuesFile, true, policyresoucePath, rc); err != nil { return rc, sanitizederror.NewWithError("failed to apply test command", err) } } - if err != nil { - sanitizederror.NewWithError("Error: failed to open file", err) - continue - } + } + if testYamlCount == 0 { + fmt.Printf("\n No test yamls available \n") } } else { path := filepath.Clean(dirPath[0]) - if err != nil { - errors = append(errors, err) - } - err := getLocalDirTestFiles(fs, path, fileName, valuesFile, rc, testYamlCount) - if err != nil { - errors = append(errors, err) - } - if len(errors) > 0 && log.Log.V(1).Enabled() { - fmt.Printf("ignoring errors: \n") - for _, e := range errors { - fmt.Printf(" %v \n", e.Error()) - } + errors = getLocalDirTestFiles(fs, path, fileName, valuesFile, rc) + } + if len(errors) > 0 && log.Log.V(1).Enabled() { + fmt.Printf("ignoring errors: \n") + for _, e := range errors { + fmt.Printf(" %v \n", e.Error()) } } if rc.fail > 0 { os.Exit(1) } - if testYamlCount == 0 { - fmt.Printf("\n No test yamls available \n") - } os.Exit(0) return rc, nil } -func getLocalDirTestFiles(fs billy.Filesystem, path, fileName, valuesFile string, rc *resultCounts, testYamlCount int) error { +func getLocalDirTestFiles(fs billy.Filesystem, path, fileName, valuesFile string, rc *resultCounts) []error { + var errors []error files, err := ioutil.ReadDir(path) if err != nil { - return fmt.Errorf("failed to read %v: %v", path, err.Error()) + return []error{fmt.Errorf("failed to read %v: %v", path, err.Error())} } for _, file := range files { if file.IsDir() { - getLocalDirTestFiles(fs, filepath.Join(path, file.Name()), fileName, valuesFile, rc, testYamlCount) + getLocalDirTestFiles(fs, filepath.Join(path, file.Name()), fileName, valuesFile, rc) continue } if strings.Contains(file.Name(), fileName) { - testYamlCount++ yamlFile, err := ioutil.ReadFile(filepath.Join(path, file.Name())) if err != nil { - sanitizederror.NewWithError("unable to read yaml", err) + errors = append(errors, sanitizederror.NewWithError("unable to read yaml", err)) continue } valuesBytes, err := yaml.ToJSON(yamlFile) if err != nil { - sanitizederror.NewWithError("failed to convert json", err) + errors = append(errors, sanitizederror.NewWithError("failed to convert json", err)) continue } if err := applyPoliciesFromPath(fs, valuesBytes, valuesFile, false, path, rc); err != nil { - sanitizederror.NewWithError("failed to apply test command", err) + errors = append(errors, sanitizederror.NewWithError(fmt.Sprintf("failed to apply test command from file %s", file.Name()), err)) continue } } } - return nil + return errors } func buildPolicyResults(resps []*response.EngineResponse) map[string][]interface{} { diff --git a/test/cli/test/policy.yaml b/test/cli/test/policy.yaml new file mode 100644 index 0000000000..81c9337d55 --- /dev/null +++ b/test/cli/test/policy.yaml @@ -0,0 +1,35 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-latest-tag + annotations: + policies.kyverno.io/category: Best Practices + policies.kyverno.io/description: >- + The ':latest' tag is mutable and can lead to unexpected errors if the + image changes. A best practice is to use an immutable tag that maps to + a specific version of an application pod. +spec: + validationFailureAction: audit + rules: + - name: require-image-tag + match: + resources: + kinds: + - Pod + validate: + message: "An image tag is required." + pattern: + spec: + containers: + - image: "*:*" + - name: validate-image-tag + match: + resources: + kinds: + - Pod + validate: + message: "Using a mutable image tag e.g. 'latest' is not allowed." + pattern: + spec: + containers: + - image: "!*:latest" diff --git a/test/cli/test/resources.yaml b/test/cli/test/resources.yaml new file mode 100644 index 0000000000..92ae8d4373 --- /dev/null +++ b/test/cli/test/resources.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-web + labels: + app: app +spec: + containers: + - name: nginx + image: nginx:latest +--- +apiVersion: v1 +kind: Pod +metadata: + name: test-app + labels: + app: app +spec: + containers: + - name: nginx + image: nginx:1.12 diff --git a/test/cli/test/test.yaml b/test/cli/test/test.yaml new file mode 100644 index 0000000000..f1063ead4d --- /dev/null +++ b/test/cli/test/test.yaml @@ -0,0 +1,14 @@ +name: test +policies: + - policy.yaml +resources: + - resources.yaml +results: + - policy: disallow-latest-tag + rule: validate-image-tag + resource: test-web + status: fail + - policy: disallow-latest-tag + rule: validate-image-tag + resource: test-app + status: pass