1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

fix: cli output improvements (#8398)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-09-14 13:45:18 +02:00 committed by GitHub
parent 1b27673a75
commit 901efbc74c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 24 additions and 36 deletions

View file

@ -87,7 +87,7 @@ func Command() *cobra.Command {
if applyCommandConfig.PolicyReport { if applyCommandConfig.PolicyReport {
printReport(out, responses, applyCommandConfig.AuditWarn) printReport(out, responses, applyCommandConfig.AuditWarn)
} else if table { } else if table {
printTable(detailedResults, applyCommandConfig.AuditWarn, responses...) printTable(out, detailedResults, applyCommandConfig.AuditWarn, responses...)
} else { } else {
printViolations(out, rc) printViolations(out, rc)
} }

View file

@ -1,13 +1,15 @@
package apply package apply
import ( import (
"io"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/table" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/table"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy/annotations" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy/annotations"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
) )
func printTable(compact, auditWarn bool, engineResponses ...engineapi.EngineResponse) { func printTable(out io.Writer, compact, auditWarn bool, engineResponses ...engineapi.EngineResponse) {
var resultsTable table.Table var resultsTable table.Table
id := 1 id := 1
for _, engineResponse := range engineResponses { for _, engineResponse := range engineResponses {
@ -49,6 +51,6 @@ func printTable(compact, auditWarn bool, engineResponses ...engineapi.EngineResp
resultsTable.Add(row) resultsTable.Add(row)
} }
} }
printer := table.NewTablePrinter() printer := table.NewTablePrinter(out)
printer.Print(resultsTable.Rows(compact)) printer.Print(resultsTable.Rows(compact))
} }

View file

@ -126,6 +126,7 @@ func testCommandExecute(
if err != nil { if err != nil {
return fmt.Errorf("failed to run test (%w)", err) return fmt.Errorf("failed to run test (%w)", err)
} }
fmt.Fprintln(out, " Checking results ...")
t, err := printTestResult(out, filteredResults, responses, rc, failOnly, detailedResults, test.Fs, resourcePath) t, err := printTestResult(out, filteredResults, responses, rc, failOnly, detailedResults, test.Fs, resourcePath)
if err != nil { if err != nil {
return fmt.Errorf("failed to print test result (%w)", err) return fmt.Errorf("failed to print test result (%w)", err)

View file

@ -22,7 +22,7 @@ func printTestResult(
fs billy.Filesystem, fs billy.Filesystem,
resoucePath string, resoucePath string,
) (table.Table, error) { ) (table.Table, error) {
printer := table.NewTablePrinter() printer := table.NewTablePrinter(out)
var resultsTable table.Table var resultsTable table.Table
var countDeprecatedResource int var countDeprecatedResource int
testCount := 1 testCount := 1
@ -99,11 +99,12 @@ func printTestResult(
} }
fmt.Fprintln(out) fmt.Fprintln(out)
printer.Print(resultsTable.Rows(detailedResults)) printer.Print(resultsTable.Rows(detailedResults))
fmt.Fprintln(out)
return resultsTable, nil return resultsTable, nil
} }
func printFailedTestResult(out io.Writer, resultsTable table.Table, detailedResults bool) { func printFailedTestResult(out io.Writer, resultsTable table.Table, detailedResults bool) {
printer := table.NewTablePrinter() printer := table.NewTablePrinter(out)
for i := range resultsTable.RawRows { for i := range resultsTable.RawRows {
resultsTable.RawRows[i].ID = i + 1 resultsTable.RawRows[i].ID = i + 1
} }

View file

@ -78,6 +78,7 @@ func runTest(out io.Writer, openApiManager openapi.Manager, testCase test.TestCa
if vars != nil { if vars != nil {
vars.SetInStore() vars.SetInStore()
} }
fmt.Fprintln(out, " Applying", len(policies), pluralize.Pluralize(len(policies), "policy", "policies"), "to", len(uniques), pluralize.Pluralize(len(uniques), "resource", "resources"), "...")
// TODO document the code below // TODO document the code below
ruleToCloneSourceResource := map[string]string{} ruleToCloneSourceResource := map[string]string{}
for _, policy := range policies { for _, policy := range policies {
@ -90,12 +91,12 @@ func runTest(out io.Writer, openApiManager openapi.Manager, testCase test.TestCa
if rule.HasGenerate() { if rule.HasGenerate() {
ruleUnstr, err := generate.GetUnstrRule(rule.Generation.DeepCopy()) ruleUnstr, err := generate.GetUnstrRule(rule.Generation.DeepCopy())
if err != nil { if err != nil {
fmt.Fprintf(out, "Error: failed to get unstructured rule\nCause: %s\n", err) fmt.Fprintf(out, " Error: failed to get unstructured rule (%s)\n", err)
break break
} }
genClone, _, err := unstructured.NestedMap(ruleUnstr.Object, "clone") genClone, _, err := unstructured.NestedMap(ruleUnstr.Object, "clone")
if err != nil { if err != nil {
fmt.Fprintf(out, "Error: failed to read data\nCause: %s\n", err) fmt.Fprintf(out, " Error: failed to read data (%s)\n", err)
break break
} }
if len(genClone) != 0 { if len(genClone) != 0 {
@ -128,14 +129,13 @@ func runTest(out io.Writer, openApiManager openapi.Manager, testCase test.TestCa
if !vars.HasVariables() && variables.NeedsVariables(matches...) { if !vars.HasVariables() && variables.NeedsVariables(matches...) {
// check policy in variable file // check policy in variable file
if !vars.HasPolicyVariables(pol.GetName()) { if !vars.HasPolicyVariables(pol.GetName()) {
fmt.Fprintf(out, "test skipped for policy %v (as required variables are not provided by the users) \n \n", pol.GetName()) fmt.Fprintln(out, " test skipped for policy", pol.GetName(), "(as required variables are not provided by the users)")
// continue // continue
} }
} }
validPolicies = append(validPolicies, pol) validPolicies = append(validPolicies, pol)
} }
// execute engine // execute engine
fmt.Fprintln(out, " Applying", len(policies), pluralize.Pluralize(len(policies), "policy", "policies"), "to", len(uniques), pluralize.Pluralize(len(uniques), "resource", "resources"), "...")
var engineResponses []engineapi.EngineResponse var engineResponses []engineapi.EngineResponse
var resultCounts processor.ResultCounts var resultCounts processor.ResultCounts

View file

@ -1,7 +1,7 @@
package table package table
import ( import (
"os" "io"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color"
"github.com/lensesio/tableprinter" "github.com/lensesio/tableprinter"
@ -11,8 +11,8 @@ func rowsLength(length int) bool {
return length > 10 return length > 10
} }
func NewTablePrinter() *tableprinter.Printer { func NewTablePrinter(out io.Writer) *tableprinter.Printer {
printer := tableprinter.New(os.Stdout) printer := tableprinter.New(out)
printer.BorderTop, printer.BorderBottom, printer.BorderLeft, printer.BorderRight = true, true, true, true printer.BorderTop, printer.BorderBottom, printer.BorderLeft, printer.BorderRight = true, true, true, true
printer.CenterSeparator = "│" printer.CenterSeparator = "│"
printer.ColumnSeparator = "│" printer.ColumnSeparator = "│"

View file

@ -1,11 +1,12 @@
package table package table
import ( import (
"os"
"testing" "testing"
) )
func TestNewTablePrinter(t *testing.T) { func TestNewTablePrinter(t *testing.T) {
if got := NewTablePrinter(); got == nil { if got := NewTablePrinter(os.Stdout); got == nil {
t.Errorf("NewTablePrinter() return nill") t.Errorf("NewTablePrinter() return nill")
} }
} }

View file

@ -176,7 +176,7 @@ func (p *PolicyProcessor) ApplyPoliciesOnResource() ([]engineapi.EngineResponse,
} }
responses = append(responses, generateResponse) responses = append(responses, generateResponse)
} }
p.Rc.addGenerateResponse(p.Out, p.AuditWarn, resPath, generateResponse) p.Rc.addGenerateResponse(p.AuditWarn, resPath, generateResponse)
} }
} }
p.Rc.addEngineResponses(p.AuditWarn, responses...) p.Rc.addEngineResponses(p.AuditWarn, responses...)
@ -307,7 +307,7 @@ func (p *PolicyProcessor) makePolicyContext(
} }
func (p *PolicyProcessor) processMutateEngineResponse(response engineapi.EngineResponse, resourcePath string) error { func (p *PolicyProcessor) processMutateEngineResponse(response engineapi.EngineResponse, resourcePath string) error {
printMutatedRes := p.Rc.addMutateResponse(p.Out, resourcePath, response) printMutatedRes := p.Rc.addMutateResponse(resourcePath, response)
if printMutatedRes && p.PrintPatchResource { if printMutatedRes && p.PrintPatchResource {
yamlEncodedResource, err := yamlv2.Marshal(response.PatchedResource.Object) yamlEncodedResource, err := yamlv2.Marshal(response.PatchedResource.Object)
if err != nil { if err != nil {

View file

@ -1,9 +1,6 @@
package processor package processor
import ( import (
"fmt"
"io"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy/annotations" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy/annotations"
"github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/autogen"
@ -75,26 +72,20 @@ func (rc *ResultCounts) addEngineResponse(auditWarn bool, response engineapi.Eng
} }
} }
func (rc *ResultCounts) addGenerateResponse(out io.Writer, auditWarn bool, resPath string, response engineapi.EngineResponse) { func (rc *ResultCounts) addGenerateResponse(auditWarn bool, resPath string, response engineapi.EngineResponse) {
genericPolicy := response.Policy() genericPolicy := response.Policy()
if polType := genericPolicy.GetType(); polType == engineapi.ValidatingAdmissionPolicyType { if polType := genericPolicy.GetType(); polType == engineapi.ValidatingAdmissionPolicyType {
return return
} }
policy := genericPolicy.GetPolicy().(kyvernov1.PolicyInterface) policy := genericPolicy.GetPolicy().(kyvernov1.PolicyInterface)
printCount := 0
for _, policyRule := range autogen.ComputeRules(policy) { for _, policyRule := range autogen.ComputeRules(policy) {
ruleFoundInEngineResponse := false ruleFoundInEngineResponse := false
for i, ruleResponse := range response.PolicyResponse.Rules { for _, ruleResponse := range response.PolicyResponse.Rules {
if policyRule.Name == ruleResponse.Name() { if policyRule.Name == ruleResponse.Name() {
ruleFoundInEngineResponse = true ruleFoundInEngineResponse = true
if ruleResponse.Status() == engineapi.RuleStatusPass { if ruleResponse.Status() == engineapi.RuleStatusPass {
rc.pass++ rc.pass++
} else { } else {
if printCount < 1 {
fmt.Fprintln(out, "\ninvalid resource", "policy", policy.GetName(), "resource", resPath)
printCount++
}
fmt.Fprintf(out, "%d. %s - %s\n", i+1, ruleResponse.Name(), ruleResponse.Message())
if auditWarn && response.GetValidationFailureAction().Audit() { if auditWarn && response.GetValidationFailureAction().Audit() {
rc.warn++ rc.warn++
} else { } else {
@ -110,7 +101,7 @@ func (rc *ResultCounts) addGenerateResponse(out io.Writer, auditWarn bool, resPa
} }
} }
func (rc *ResultCounts) addMutateResponse(out io.Writer, resourcePath string, response engineapi.EngineResponse) bool { func (rc *ResultCounts) addMutateResponse(resourcePath string, response engineapi.EngineResponse) bool {
genericPolicy := response.Policy() genericPolicy := response.Policy()
if polType := genericPolicy.GetType(); polType == engineapi.ValidatingAdmissionPolicyType { if polType := genericPolicy.GetType(); polType == engineapi.ValidatingAdmissionPolicyType {
return false return false
@ -125,28 +116,20 @@ func (rc *ResultCounts) addMutateResponse(out io.Writer, resourcePath string, re
if !policyHasMutate { if !policyHasMutate {
return false return false
} }
printCount := 0
printMutatedRes := false printMutatedRes := false
for _, policyRule := range autogen.ComputeRules(policy) { for _, policyRule := range autogen.ComputeRules(policy) {
ruleFoundInEngineResponse := false ruleFoundInEngineResponse := false
for i, mutateResponseRule := range response.PolicyResponse.Rules { for _, mutateResponseRule := range response.PolicyResponse.Rules {
if policyRule.Name == mutateResponseRule.Name() { if policyRule.Name == mutateResponseRule.Name() {
ruleFoundInEngineResponse = true ruleFoundInEngineResponse = true
if mutateResponseRule.Status() == engineapi.RuleStatusPass { if mutateResponseRule.Status() == engineapi.RuleStatusPass {
rc.pass++ rc.pass++
printMutatedRes = true printMutatedRes = true
} else if mutateResponseRule.Status() == engineapi.RuleStatusSkip { } else if mutateResponseRule.Status() == engineapi.RuleStatusSkip {
fmt.Fprintf(out, "\nskipped mutate policy %s -> resource %s", policy.GetName(), resourcePath)
rc.skip++ rc.skip++
} else if mutateResponseRule.Status() == engineapi.RuleStatusError { } else if mutateResponseRule.Status() == engineapi.RuleStatusError {
fmt.Fprintf(out, "\nerror while applying mutate policy %s -> resource %s\nerror: %s", policy.GetName(), resourcePath, mutateResponseRule.Message())
rc.err++ rc.err++
} else { } else {
if printCount < 1 {
fmt.Fprintf(out, "\nfailed to apply mutate policy %s -> resource %s", policy.GetName(), resourcePath)
printCount++
}
fmt.Fprintf(out, "%d. %s - %s \n", i+1, mutateResponseRule.Name(), mutateResponseRule.Message())
rc.fail++ rc.fail++
} }
continue continue