Skip to content

Commit

Permalink
feat: add labels flag as optional
Browse files Browse the repository at this point in the history
  • Loading branch information
femrtnz committed Oct 1, 2024
1 parent 8582f7c commit 5908968
Show file tree
Hide file tree
Showing 22 changed files with 258 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,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.OptionalFlags)
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, optionalFlags config.OptionalFlags) 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, optionalFlags)
if err != nil {
return fmt.Errorf("failed to print results: %v", err)
}
Expand Down
15 changes: 8 additions & 7 deletions cmd/kubent/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,23 +272,24 @@ func Test_outputResults(t *testing.T) {
ApiVersion: "1.2.3", RuleSet: "rs", ReplaceWith: "rep", Since: testVersion}}

type args struct {
results []judge.Result
outputType string
outputFile string
results []judge.Result
outputType string
outputFile string
optionalFlags config.OptionalFlags
}
tests := []struct {
name string
args args
wantErr bool
}{
{"good", args{testResults, "text", "-"}, false},
{"bad-new-printer-type", args{testResults, "unknown", "-"}, true},
{"bad-new-printer-file", args{testResults, "text", "/unlikely/to/exist/dir"}, true},
{"good", args{testResults, "text", "-", config.OptionalFlags{Labels: false}}, false},
{"bad-new-printer-type", args{testResults, "unknown", "-", config.OptionalFlags{Labels: false}}, true},
{"bad-new-printer-file", args{testResults, "text", "/unlikely/to/exist/dir", config.OptionalFlags{Labels: false}}, true},
}

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, tt.args.optionalFlags); (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
29 changes: 26 additions & 3 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ import (
"unicode"

"github.com/doitintl/kube-no-trouble/pkg/judge"
"github.com/doitintl/kube-no-trouble/pkg/printer"
"k8s.io/client-go/tools/clientcmd"

"github.com/rs/zerolog"
flag "github.com/spf13/pflag"
)

const (
JSON = "json"
TEXT = "text"
CSV = "csv"
)

type Config struct {
AdditionalKinds []string
AdditionalAnnotations []string
Expand All @@ -31,12 +36,18 @@ type Config struct {
OutputFile string
TargetVersion *judge.Version
KubentVersion bool
OptionalFlags *OptionalFlags
}

type OptionalFlags struct {
Labels bool
}

func NewFromFlags() (*Config, error) {
config := Config{
LogLevel: ZeroLogLevel(zerolog.InfoLevel),
TargetVersion: &judge.Version{},
OptionalFlags: &OptionalFlags{},
}

flag.StringSliceVarP(&config.AdditionalKinds, "additional-kind", "a", []string{}, "additional kinds of resources to report in Kind.version.group.com format")
Expand All @@ -52,11 +63,12 @@ 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.OptionalFlags.Labels, "labels", false, "print resource labels")

flag.Parse()

if _, err := printer.ParsePrinter(config.Output); err != nil {
return nil, fmt.Errorf("failed to validate argument output: %w", err)
if !isValidOutputFormat(config.Output) {
return nil, fmt.Errorf("failed to validate argument output: %s", config.Output)
}

if err := validateOutputFile(config.OutputFile); err != nil {
Expand All @@ -77,6 +89,17 @@ func NewFromFlags() (*Config, error) {
return &config, nil
}

// Previuosly this was handled by a printer.go ParsePrinter function
// but we need to avoid cycle imports in order to inject the additional flags
func isValidOutputFormat(format string) bool {
switch format {
case JSON, TEXT, CSV:
return true
default:
return false
}
}

// validateAdditionalResources check that all resources are provided in full form
// resource.version.group.com. E.g. managedcertificate.v1beta1.networking.gke.io
func validateAdditionalResources(resources []string) error {
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
23 changes: 18 additions & 5 deletions pkg/printer/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"sort"

"github.com/doitintl/kube-no-trouble/pkg/config"
"github.com/doitintl/kube-no-trouble/pkg/judge"
)

Expand All @@ -29,7 +30,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, optionalFlags config.OptionalFlags) error {

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

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

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

if optionalFlags.Labels {
fields = append(fields, "labels")
}

w.Write(fields)

for _, r := range results {
w.Write([]string{
row := []string{
r.ApiVersion,
r.Kind,
r.Namespace,
r.Name,
r.ReplaceWith,
r.Since.String(),
r.RuleSet,
})
}

if optionalFlags.Labels {
row = append(row, mapToCommaSeparatedString(r.Labels))
}

w.Write(row)
}

w.Flush()
Expand Down
7 changes: 5 additions & 2 deletions pkg/printer/csv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"testing"

"github.com/doitintl/kube-no-trouble/pkg/config"
"github.com/doitintl/kube-no-trouble/pkg/judge"
)

Expand Down Expand Up @@ -51,9 +52,11 @@ 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}}
labels := map[string]interface{}{"key1": "value1"}

if err := tp.Print(results); err != nil {
results := []judge.Result{{Name: "Name", Namespace: "Namespace", Kind: "Kind", ApiVersion: "1.2.3", RuleSet: "Test", ReplaceWith: "4.5.6", Since: version, Labels: labels}}

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

Expand Down
3 changes: 2 additions & 1 deletion pkg/printer/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"

"github.com/doitintl/kube-no-trouble/pkg/config"
"github.com/doitintl/kube-no-trouble/pkg/judge"
)

Expand All @@ -29,7 +30,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, _ config.OptionalFlags) error {
writer := bufio.NewWriter(c.commonPrinter.outputFile)
defer writer.Flush()

Expand Down
16 changes: 13 additions & 3 deletions pkg/printer/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"
"testing"

"github.com/doitintl/kube-no-trouble/pkg/config"
"github.com/doitintl/kube-no-trouble/pkg/judge"
)

Expand Down Expand Up @@ -40,7 +41,6 @@ func Test_newJSONPrinter(t *testing.T) {
})
}
}

func Test_jsonPrinter_Print(t *testing.T) {
tmpFile, err := ioutil.TempFile(os.TempDir(), tempFilePrefix)
if err != nil {
Expand All @@ -53,9 +53,19 @@ 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}}
labels := map[string]interface{}{"key1": "value1"}

if err := c.Print(results); err != nil {
results := []judge.Result{{
Name: "Name",
Namespace: "Namespace",
Kind: "Kind",
ApiVersion: "1.2.3",
RuleSet: "Test",
ReplaceWith: "4.5.6",
Since: version,
Labels: labels,
}}
if err := c.Print(results, config.OptionalFlags{Labels: true}); err != nil {
t.Fatalf("unexpected error: %v", err)
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"

"github.com/doitintl/kube-no-trouble/pkg/config"
"github.com/doitintl/kube-no-trouble/pkg/judge"
)

Expand All @@ -14,7 +15,7 @@ var printers = map[string]func(string) (Printer, error){
}

type Printer interface {
Print([]judge.Result) error
Print([]judge.Result, config.OptionalFlags) 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()
}
Loading

0 comments on commit 5908968

Please sign in to comment.