Skip to content

Commit

Permalink
feat: Add labels flag and output
Browse files Browse the repository at this point in the history
  • Loading branch information
femrtnz committed Sep 28, 2024
1 parent 84d2b10 commit 6439760
Show file tree
Hide file tree
Showing 22 changed files with 276 additions and 43 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Otherwise there's `Makefile`
```sh
$ make
make
all Cean, build and pack
all Clean, build and pack
help Prints list of tasks
build Build binary
generate Go generate
Expand Down
6 changes: 3 additions & 3 deletions cmd/kubent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func main() {
log.Fatal().Err(err).Str("name", "Rego").Msg("Failed to filter results")
}

err = outputResults(results, config.Output, config.OutputFile)
err = outputResults(results, config.Output, config.OutputFile, config.Labels)
if err != nil {
log.Fatal().Err(err).Msgf("Failed to output results")
}
Expand All @@ -180,14 +180,14 @@ func configureGlobalLogging() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}

func outputResults(results []judge.Result, outputType string, outputFile string) error {
func outputResults(results []judge.Result, outputType string, outputFile string, labels bool) error {
printer, err := printer.NewPrinter(outputType, outputFile)
if err != nil {
return fmt.Errorf("failed to create printer: %v", err)
}
defer printer.Close()

err = printer.Print(results)
err = printer.Print(results, labels)
if err != nil {
return fmt.Errorf("failed to print results: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubent/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func Test_outputResults(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := outputResults(tt.args.results, tt.args.outputType, tt.args.outputFile); (err != nil) != tt.wantErr {
if err := outputResults(tt.args.results, tt.args.outputType, tt.args.outputFile, false); (err != nil) != tt.wantErr {
t.Errorf("unexpected error - got: %v, wantErr: %v", err, tt.wantErr)
}
})
Expand Down
3 changes: 2 additions & 1 deletion fixtures/expected-json-output.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"ApiVersion": "apps/v1beta1",
"RuleSet": "Deprecated APIs removed in 1.16",
"ReplaceWith": "apps/v1",
"Since": "1.9.0"
"Since": "1.9.0",
"Labels": {}
}
]
2 changes: 1 addition & 1 deletion pkg/collector/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestFileCollectorGet(t *testing.T) {
t.Errorf("Expected to get %d, got %d", len(tc.expected), len(manifests))
}

for i, _ := range manifests {
for i := range manifests {
if manifests[i]["kind"] != tc.expected[i] {
t.Errorf("Expected to get %s, instead got: %s", tc.expected[i], manifests[i]["kind"])
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Config struct {
OutputFile string
TargetVersion *judge.Version
KubentVersion bool
Labels bool
}

func NewFromFlags() (*Config, error) {
Expand All @@ -52,6 +53,7 @@ func NewFromFlags() (*Config, error) {
flag.StringVarP(&config.OutputFile, "output-file", "O", "-", "output file, use - for stdout")
flag.VarP(&config.LogLevel, "log-level", "l", "set log level (trace, debug, info, warn, error, fatal, panic, disabled)")
flag.VarP(config.TargetVersion, "target-version", "t", "target K8s version in SemVer format (autodetected by default)")
flag.BoolVar(&config.Labels, "labels", false, "print resource labels")

flag.Parse()

Expand Down
6 changes: 3 additions & 3 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ func TestValidateAdditionalResources(t *testing.T) {

func TestValidateAdditionalResourcesFail(t *testing.T) {
testCases := [][]string{
[]string{"abcdef"},
[]string{""},
[]string{"test.v1.com"},
{"abcdef"},
{""},
{"test.v1.com"},
}

for _, tc := range testCases {
Expand Down
1 change: 1 addition & 0 deletions pkg/judge/judge.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Result struct {
RuleSet string
ReplaceWith string
Since *Version
Labels map[string]interface{}
}

type Judge interface {
Expand Down
7 changes: 7 additions & 0 deletions pkg/judge/rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ func (j *RegoJudge) Eval(input []map[string]interface{}) ([]Result, error) {
m["Namespace"] = "<undefined>"
}

var labels map[string]interface{}
if v, ok := m["Labels"].(map[string]interface{}); ok {
labels = v
} else {
labels = make(map[string]interface{})
}
results = append(results, Result{
Name: m["Name"].(string),
Namespace: m["Namespace"].(string),
Expand All @@ -71,6 +77,7 @@ func (j *RegoJudge) Eval(input []map[string]interface{}) ([]Result, error) {
ReplaceWith: m["ReplaceWith"].(string),
RuleSet: m["RuleSet"].(string),
Since: since,
Labels: labels,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/judge/rego_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func TestEvalRules(t *testing.T) {
t.Errorf("expected %d findings, instead got: %d", len(tc.expected), len(results))
}

for i, _ := range results {
for i := range results {
if results[i].Kind != tc.expected[i] {
t.Errorf("expected to get %s finding, instead got: %s", tc.expected[i], results[i].Kind)
}
Expand Down
62 changes: 43 additions & 19 deletions pkg/printer/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (c *csvPrinter) Close() error {
}

// Print will print results in CSV format
func (c *csvPrinter) Print(results []judge.Result) error {
func (c *csvPrinter) Print(results []judge.Result, labels bool) error {

sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
Expand All @@ -46,26 +46,50 @@ func (c *csvPrinter) Print(results []judge.Result) error {

w := csv.NewWriter(c.commonPrinter.outputFile)

w.Write([]string{
"api_version",
"kind",
"namespace",
"name",
"replace_with",
"since",
"rule_set",
})

for _, r := range results {
if labels {
w.Write([]string{
"api_version",
"kind",
"namespace",
"name",
"replace_with",
"since",
"rule_set",
"labels",
})
for _, r := range results {
w.Write([]string{
r.ApiVersion,
r.Kind,
r.Namespace,
r.Name,
r.ReplaceWith,
r.Since.String(),
r.RuleSet,
mapToCommaSeparatedString(r.Labels),
})
}
} else {
w.Write([]string{
r.ApiVersion,
r.Kind,
r.Namespace,
r.Name,
r.ReplaceWith,
r.Since.String(),
r.RuleSet,
"api_version",
"kind",
"namespace",
"name",
"replace_with",
"since",
"rule_set",
})
for _, r := range results {
w.Write([]string{
r.ApiVersion,
r.Kind,
r.Namespace,
r.Name,
r.ReplaceWith,
r.Since.String(),
r.RuleSet,
})
}
}

w.Flush()
Expand Down
46 changes: 44 additions & 2 deletions pkg/printer/csv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,51 @@ func TestCSVPrinterPrint(t *testing.T) {
}

version, _ := judge.NewVersion("1.2.3")
results := []judge.Result{{"Name", "Namespace", "Kind", "1.2.3", "Test", "4.5.6", version}}
results := []judge.Result{{
Name: "Name",
Namespace: "Namespace",
Kind: "Kind",
ApiVersion: "1.2.3",
RuleSet: "Test",
ReplaceWith: "4.5.6",
Since: version,
Labels: map[string]interface{}{"app": "php-apache-app"},
}}

if err := tp.Print(results); err != nil {
if err := tp.Print(results, true); err != nil {
t.Fatalf("unexpected error: %v", err)
}

fi, _ := tmpFile.Stat()
if fi.Size() == 0 {
t.Fatalf("expected non-zero size output file: %v", err)
}
}

func TestCSVPrinterPrintNoLabels(t *testing.T) {
tmpFile, err := ioutil.TempFile(os.TempDir(), tempFilePrefix)
if err != nil {
t.Fatalf(tempFileCreateFailureMessage, err)
}
defer os.Remove(tmpFile.Name())

tp := &csvPrinter{
commonPrinter: &commonPrinter{tmpFile},
}

version, _ := judge.NewVersion("1.2.3")
results := []judge.Result{{
Name: "Name",
Namespace: "Namespace",
Kind: "Kind",
ApiVersion: "1.2.3",
RuleSet: "Test",
ReplaceWith: "4.5.6",
Since: version,
Labels: map[string]interface{}{},
}}

if err := tp.Print(results, false); err != nil {
t.Fatalf("unexpected error: %v", err)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/printer/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (c *jsonPrinter) Close() error {
}

// Print will print results in text format
func (c *jsonPrinter) Print(results []judge.Result) error {
func (c *jsonPrinter) Print(results []judge.Result, labels bool) error {
writer := bufio.NewWriter(c.commonPrinter.outputFile)
defer writer.Flush()

Expand Down
55 changes: 53 additions & 2 deletions pkg/printer/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,60 @@ func Test_jsonPrinter_Print(t *testing.T) {
}

version, _ := judge.NewVersion("1.2.3")
results := []judge.Result{{"Name", "Namespace", "Kind", "1.2.3", "Test", "4.5.6", version}}
results := []judge.Result{{
Name: "Name",
Namespace: "Namespace",
Kind: "Kind",
ApiVersion: "1.2.3",
RuleSet: "Test",
ReplaceWith: "4.5.6",
Since: version,
Labels: map[string]interface{}{"label1": "value1", "label2": "value2"},
}}

if err := c.Print(results); err != nil {
if err := c.Print(results, true); err != nil {
t.Fatalf("unexpected error: %v", err)
}

tmpFile.Seek(0, 0)

var readResults []judge.Result
readBytes, err := ioutil.ReadAll(tmpFile)
if err != nil {
t.Fatalf("unexpected error reading back the file: %v", err)
}
if err := json.Unmarshal(readBytes, &readResults); err != nil {
t.Fatalf("unexpected error unmarshalling the previously written file: %v", err)
}
if !reflect.DeepEqual(readResults, results) {
t.Fatalf("written and read result do not seem to be equal")
}
}

func Test_jsonPrinter_PrintNoLabel(t *testing.T) {
tmpFile, err := ioutil.TempFile(os.TempDir(), tempFilePrefix)
if err != nil {
t.Fatalf(tempFileCreateFailureMessage, err)
}
defer os.Remove(tmpFile.Name())

c := &jsonPrinter{
commonPrinter: &commonPrinter{tmpFile},
}

version, _ := judge.NewVersion("1.2.3")
results := []judge.Result{{
Name: "Name",
Namespace: "Namespace",
Kind: "Kind",
ApiVersion: "1.2.3",
RuleSet: "Test",
ReplaceWith: "4.5.6",
Since: version,
Labels: map[string]interface{}{},
}}

if err := c.Print(results, false); err != nil {
t.Fatalf("unexpected error: %v", err)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var printers = map[string]func(string) (Printer, error){
}

type Printer interface {
Print([]judge.Result) error
Print([]judge.Result, bool) error
Close() error
}

Expand Down
17 changes: 17 additions & 0 deletions pkg/printer/printer_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package printer

import (
"fmt"
"strings"
)

func mapToCommaSeparatedString(m map[string]interface{}) string {
var sb strings.Builder
for k, v := range m {
if sb.Len() > 0 {
sb.WriteString(", ")
}
sb.WriteString(fmt.Sprintf("%s:%v", k, v))
}
return sb.String()
}
36 changes: 36 additions & 0 deletions pkg/printer/printer_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package printer

import (
"testing"
)

func TestMapToCommaSeparatedString(t *testing.T) {
tests := []struct {
input map[string]interface{}
expected string
}{
{
input: map[string]interface{}{},
expected: "",
},
{
input: map[string]interface{}{"key1": "value1"},
expected: "key1:value1",
},
{
input: map[string]interface{}{"key1": "value1", "key2": "value2"},
expected: "key1:value1, key2:value2",
},
{
input: map[string]interface{}{"key1": 123, "key2": true, "key3": 45.67},
expected: "key1:123, key2:true, key3:45.67",
},
}

for _, test := range tests {
result := mapToCommaSeparatedString(test.input)
if result != test.expected {
t.Errorf("For input %v, expected %s but got %s", test.input, test.expected, result)
}
}
}
Loading

0 comments on commit 6439760

Please sign in to comment.