From cfdae4d035b5895b463b177e2f2f2c96d67c7f8c Mon Sep 17 00:00:00 2001
From: myishay <myishay@gmail.com>
Date: Wed, 19 May 2021 20:22:27 +0300
Subject: [PATCH] wip: invalid files

---
 bl/evaluation/evaluator.go    | 13 ++++++--
 bl/evaluation/printer.go      |  9 +++++
 bl/validation/k8sValidator.go | 63 ++++++++++++++++++-----------------
 cmd/test/main.go              | 11 +++---
 pkg/cliClient/evaluation.go   |  2 +-
 pkg/printer/printer.go        | 14 ++++++--
 6 files changed, 70 insertions(+), 42 deletions(-)

diff --git a/bl/evaluation/evaluator.go b/bl/evaluation/evaluator.go
index b6ebc4c..a62a1c1 100644
--- a/bl/evaluation/evaluator.go
+++ b/bl/evaluation/evaluator.go
@@ -1,6 +1,7 @@
 package evaluation
 
 import (
+	"github.com/datreeio/datree/bl/validation"
 	"github.com/datreeio/datree/pkg/cliClient"
 	"github.com/datreeio/datree/pkg/extractor"
 )
@@ -52,10 +53,14 @@ func (e *Evaluator) CreateEvaluation(cliId string, cliVersion string) (int, erro
 	return evaluationId, err
 }
 
-func (e *Evaluator) Evaluate(validFilesPathsChan chan string, invalidFilesPaths []*string, evaluationId int) (*EvaluationResults, []*Error, error) {
+func (e *Evaluator) Evaluate(validFilesPathsChan chan string, invalidFiles []validation.InvalidFile, evaluationId int) (*EvaluationResults, []*Error, error) {
 	filesConfigurations, errors := e.extractFilesConfigurations(validFilesPathsChan)
 
-	if len(invalidFilesPaths) > 0 {
+	if len(invalidFiles) > 0 {
+		var invalidFilesPaths []*string
+		for _, file := range invalidFiles {
+			invalidFilesPaths = append(invalidFilesPaths, &file.Path)
+		}
 		stopEvaluation := len(validFilesPathsChan) == 0 // NOTICE: validFilesPathsChan surely closed and empty
 		err := e.cliClient.UpdateEvaluationValidation(&cliClient.UpdateEvaluationValidationRequest{
 			EvaluationId:   evaluationId,
@@ -63,7 +68,9 @@ func (e *Evaluator) Evaluate(validFilesPathsChan chan string, invalidFilesPaths
 			StopEvaluation: stopEvaluation,
 		})
 
-		return nil, errors, err
+		if stopEvaluation {
+			return nil, errors, err
+		}
 	}
 
 	if len(filesConfigurations) > 0 {
diff --git a/bl/evaluation/printer.go b/bl/evaluation/printer.go
index b3b89ff..4f22f14 100644
--- a/bl/evaluation/printer.go
+++ b/bl/evaluation/printer.go
@@ -15,6 +15,10 @@ type Printer interface {
 	PrintSummaryTable(summary printer.Summary)
 }
 
+// func PrintAllResults(results *EvaluationResults /*, invalidFiles*/) {
+// 	// TODO: foreach invalid file
+// }
+
 // url := "https://app.datree.io/login?cliId=" + cliId
 func PrintResults(results *EvaluationResults, loginURL string, outputFormat string, printer Printer) error {
 	switch {
@@ -91,6 +95,11 @@ func parseToPrinterWarnings(results *EvaluationResults, pwd string) ([]printer.W
 		warnings = append(warnings, printer.Warning{
 			Title:   fmt.Sprintf(">>  File: %s\n", relativePath),
 			Details: warningDetails,
+			ValidationInfo: printer.ValidationInfo{
+				IsValid:    true,
+				ErrMsgStr:  "",
+				K8sVersion: "1.18.0",
+			},
 		})
 	}
 
diff --git a/bl/validation/k8sValidator.go b/bl/validation/k8sValidator.go
index 6cbd45f..d3418bd 100644
--- a/bl/validation/k8sValidator.go
+++ b/bl/validation/k8sValidator.go
@@ -24,55 +24,58 @@ func New(k8sVersion string) *K8sValidator {
 	}
 }
 
-func (val *K8sValidator) ValidateResources(paths []string) (chan string, []*string, chan error) {
+type InvalidFile struct {
+	Path             string
+	ValidationErrors []error
+}
+
+func (val *K8sValidator) ValidateResources(paths []string) (chan string, []InvalidFile, chan error) {
 	pathsChan := files.ToAbsolutePaths(paths)
 
-	var invalidFilesPaths = []*string{}
+	var invalidFiles []InvalidFile
 	errorChan := make(chan error)
 	validFilesPathChan := make(chan string)
 
-	go func() {
-		for path := range pathsChan {
-			isValid, err := val.validateResource(path)
-			if isValid {
-				validFilesPathChan <- path
-			} else {
-				invalidFilesPaths = append(invalidFilesPaths, &path)
-			}
-			if err != nil {
-				errorChan <- err
-			}
+	for path := range pathsChan {
+		isValid, validationErrors, err := val.validateResource(path)
+		if isValid {
+			validFilesPathChan <- path
+		} else {
+			invalidFiles = append(invalidFiles, InvalidFile{
+				Path:             path,
+				ValidationErrors: validationErrors,
+			})
 		}
-		close(validFilesPathChan)
-		close(errorChan)
-	}()
+		if err != nil {
+			errorChan <- err
+		}
+	}
+	close(validFilesPathChan)
+	close(errorChan)
 
-	return validFilesPathChan, invalidFilesPaths, errorChan
+	return validFilesPathChan, invalidFiles, errorChan
 }
 
-func (val *K8sValidator) validateResource(filepath string) (bool, error) {
+func (val *K8sValidator) validateResource(filepath string) (bool, []error, error) {
 	f, err := os.Open(filepath)
 	if err != nil {
-		return false, fmt.Errorf("failed opening %s: %s", filepath, err)
+		return false, []error{}, fmt.Errorf("failed opening %s: %s", filepath, err)
 	}
 
 	results := val.validationClient.Validate(filepath, f)
-	isValid := false
-	for i, res := range results {
-		if res.Status == kubeconformValidator.Valid {
-			isValid = true
-		}
+	isValid := true
+	var validationErrors []error
+	for _, res := range results {
+
 		// A file might contain multiple resources
 		// File starts with ---, the parser assumes a first empty resource
-		if res.Status == kubeconformValidator.Invalid {
-			fmt.Errorf("resource %d in file %s is not valid: %s", i, filepath, res.Err)
-		}
-		if res.Status == kubeconformValidator.Error {
-			fmt.Errorf("error while processing resource %d in file %s: %s", i, filepath, res.Err)
+		if res.Status == kubeconformValidator.Invalid || res.Status == kubeconformValidator.Error {
+			isValid = false
+			validationErrors = append(validationErrors, res.Err)
 		}
 	}
 
-	return isValid, nil
+	return isValid, validationErrors, nil
 }
 
 func newKubconformValidator(k8sVersion string) ValidationClient {
diff --git a/cmd/test/main.go b/cmd/test/main.go
index c29ec5f..0c648a1 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -7,13 +7,14 @@ import (
 	"github.com/briandowns/spinner"
 	"github.com/datreeio/datree/bl/evaluation"
 	"github.com/datreeio/datree/bl/messager"
+	"github.com/datreeio/datree/bl/validation"
 	"github.com/datreeio/datree/pkg/localConfig"
 	"github.com/datreeio/datree/pkg/printer"
 	"github.com/spf13/cobra"
 )
 
 type Evaluator interface {
-	Evaluate(validFilesPathsChan chan string, invalidFilesPaths []*string, evaluationId int) (*evaluation.EvaluationResults, []*evaluation.Error, error)
+	Evaluate(validFilesPathsChan chan string, invalidFilesPaths []validation.InvalidFile, evaluationId int) (*evaluation.EvaluationResults, []*evaluation.Error, error)
 	CreateEvaluation(cliId string, cliVersion string) (int, error)
 }
 
@@ -22,7 +23,7 @@ type Messager interface {
 }
 
 type K8sValidator interface {
-	ValidateResources(paths []string) (chan string, []*string, chan error)
+	ValidateResources(paths []string) (chan string, []validation.InvalidFile, chan error)
 }
 
 type TestCommandFlags struct {
@@ -73,10 +74,10 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 	messages := make(chan *messager.VersionMessage, 1)
 	go ctx.Messager.LoadVersionMessages(messages, ctx.CliVersion)
 
-	validFilesPaths, invalidFilesPaths, errorsChan := ctx.K8sValidator.ValidateResources(paths)
+	validFilesPaths, invalidFiles, errorsChan := ctx.K8sValidator.ValidateResources(paths)
 	go func() {
 		for err := range errorsChan {
-			fmt.Print(err)
+			fmt.Println(err)
 		}
 	}()
 
@@ -86,7 +87,7 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 		return err
 	}
 
-	results, errors, err := ctx.Evaluator.Evaluate(validFilesPaths, invalidFilesPaths, evaluationId)
+	results, errors, err := ctx.Evaluator.Evaluate(validFilesPaths, invalidFiles, evaluationId)
 
 	spinner.Stop()
 
diff --git a/pkg/cliClient/evaluation.go b/pkg/cliClient/evaluation.go
index 686aa09..5294df9 100644
--- a/pkg/cliClient/evaluation.go
+++ b/pkg/cliClient/evaluation.go
@@ -87,7 +87,7 @@ func (c *CliClient) RequestEvaluation(request *EvaluationRequest) (*EvaluationRe
 type UpdateEvaluationValidationRequest struct {
 	EvaluationId   int       `json:"evaluationId"`
 	InvalidFiles   []*string `json:"failedFiles"`
-	StopEvaluation bool
+	StopEvaluation bool      `json:"stopEvaluation"`
 }
 
 func (c *CliClient) UpdateEvaluationValidation(request *UpdateEvaluationValidationRequest) error {
diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go
index efd51f8..5b2c998 100644
--- a/pkg/printer/printer.go
+++ b/pkg/printer/printer.go
@@ -25,15 +25,23 @@ type WarningInfo struct {
 	Suggestion  string
 }
 
+type ValidationInfo struct {
+	IsValid    bool
+	ErrMsgStr  string
+	K8sVersion string
+}
 type Warning struct {
-	Title   string
-	Details []WarningInfo
+	Title          string
+	Details        []WarningInfo
+	ValidationInfo ValidationInfo
 }
 
 func (p *Printer) PrintWarnings(warnings []Warning) {
 	for _, warning := range warnings {
 		p.printInColor(warning.Title, p.theme.Colors.Yellow)
-
+		fmt.Println()
+		p.printInColor("[V] Kubernetes schema validation\n", p.theme.Colors.Green)
+		p.printInColor("[X] Policy check\n", p.theme.Colors.White)
 		fmt.Println()
 
 		for _, d := range warning.Details {
-- 
GitLab