Skip to content

Commit c6f59f0

Browse files
author
Felipe Amaral
committed
feat: Adding labels flag as optional flag
1 parent 8582f7c commit c6f59f0

31 files changed

+336
-53
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ Otherwise there's `Makefile`
223223
```sh
224224
$ make
225225
make
226-
all Cean, build and pack
226+
all Clean, build and pack
227227
help Prints list of tasks
228228
build Build binary
229229
generate Go generate

cmd/kubent/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"flag"
56
"fmt"
67
"io"
@@ -96,11 +97,13 @@ func getServerVersion(cv *judge.Version, collectors []collector.Collector) (*jud
9697
}
9798

9899
func main() {
100+
ctx := context.Background()
99101
exitCode := EXIT_CODE_FAIL_GENERIC
100102

101103
configureGlobalLogging()
102104

103-
config, err := config.NewFromFlags()
105+
config, ctx, err := config.NewFromFlags(ctx)
106+
104107
if err != nil {
105108
log.Fatal().Err(err).Msg("failed to parse config flags")
106109
}
@@ -156,7 +159,7 @@ func main() {
156159
log.Fatal().Err(err).Str("name", "Rego").Msg("Failed to filter results")
157160
}
158161

159-
err = outputResults(results, config.Output, config.OutputFile)
162+
err = outputResults(results, config.Output, config.OutputFile, ctx)
160163
if err != nil {
161164
log.Fatal().Err(err).Msgf("Failed to output results")
162165
}
@@ -180,14 +183,14 @@ func configureGlobalLogging() {
180183
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
181184
}
182185

183-
func outputResults(results []judge.Result, outputType string, outputFile string) error {
186+
func outputResults(results []judge.Result, outputType string, outputFile string, ctx context.Context) error {
184187
printer, err := printer.NewPrinter(outputType, outputFile)
185188
if err != nil {
186189
return fmt.Errorf("failed to create printer: %v", err)
187190
}
188191
defer printer.Close()
189192

190-
err = printer.Print(results)
193+
err = printer.Print(results, ctx)
191194
if err != nil {
192195
return fmt.Errorf("failed to print results: %v", err)
193196
}

cmd/kubent/main_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"bytes"
5+
"context"
56
"encoding/base64"
67
"encoding/json"
78
"errors"
@@ -13,6 +14,7 @@ import (
1314

1415
"github.com/doitintl/kube-no-trouble/pkg/collector"
1516
"github.com/doitintl/kube-no-trouble/pkg/config"
17+
ctxKey "github.com/doitintl/kube-no-trouble/pkg/context"
1618
"github.com/doitintl/kube-no-trouble/pkg/judge"
1719

1820
"github.com/rs/zerolog"
@@ -120,7 +122,7 @@ func TestMainExitCodes(t *testing.T) {
120122
}{
121123
{"success", []string{clusterFlagDisabled, helm3FlagDisabled}, 0, "", "", false},
122124
{"errorBadFlag", []string{"-c=not-boolean"}, 2, "", "", false},
123-
{"successFound", []string{"-o=json", clusterFlagDisabled, helm3FlagDisabled, "-f=" + filepath.Join(FIXTURES_DIR, "deployment-v1beta1.yaml")}, 0, string(expectedJsonOutput), "", false},
125+
{"successFound", []string{"--labels=true", "-o=json", clusterFlagDisabled, helm3FlagDisabled, "-f=" + filepath.Join(FIXTURES_DIR, "deployment-v1beta1.yaml")}, 0, string(expectedJsonOutput), "", false},
124126
{"exitErrorFlagNone", []string{clusterFlagDisabled, helm3FlagDisabled, "-e"}, 0, "", "", false},
125127
{"exitErrorFlagFound", []string{clusterFlagDisabled, helm3FlagDisabled, "-e", "-f=" + filepath.Join(FIXTURES_DIR, "deployment-v1beta1.yaml")}, 200, "", "", false},
126128
{"version short flag set", []string{"-v"}, 0, "", "", false},
@@ -286,9 +288,12 @@ func Test_outputResults(t *testing.T) {
286288
{"bad-new-printer-file", args{testResults, "text", "/unlikely/to/exist/dir"}, true},
287289
}
288290

291+
labelsFlag := false
292+
ctx := context.WithValue(context.Background(), ctxKey.LABELS_CTX_KEY, &labelsFlag)
293+
289294
for _, tt := range tests {
290295
t.Run(tt.name, func(t *testing.T) {
291-
if err := outputResults(tt.args.results, tt.args.outputType, tt.args.outputFile); (err != nil) != tt.wantErr {
296+
if err := outputResults(tt.args.results, tt.args.outputType, tt.args.outputFile, ctx); (err != nil) != tt.wantErr {
292297
t.Errorf("unexpected error - got: %v, wantErr: %v", err, tt.wantErr)
293298
}
294299
})

fixtures/expected-json-output.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"ApiVersion": "apps/v1beta1",
77
"RuleSet": "Deprecated APIs removed in 1.16",
88
"ReplaceWith": "apps/v1",
9-
"Since": "1.9.0"
9+
"Since": "1.9.0",
10+
"Labels": {
11+
"app": "nginx"
12+
}
1013
}
1114
]

pkg/collector/file_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestFileCollectorGet(t *testing.T) {
5252
t.Errorf("Expected to get %d, got %d", len(tc.expected), len(manifests))
5353
}
5454

55-
for i, _ := range manifests {
55+
for i := range manifests {
5656
if manifests[i]["kind"] != tc.expected[i] {
5757
t.Errorf("Expected to get %s, instead got: %s", tc.expected[i], manifests[i]["kind"])
5858
}

pkg/config/config.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"context"
45
"errors"
56
"fmt"
67
"io/fs"
@@ -9,14 +10,20 @@ import (
910
"strings"
1011
"unicode"
1112

13+
ctxKey "github.com/doitintl/kube-no-trouble/pkg/context"
1214
"github.com/doitintl/kube-no-trouble/pkg/judge"
13-
"github.com/doitintl/kube-no-trouble/pkg/printer"
1415
"k8s.io/client-go/tools/clientcmd"
1516

1617
"github.com/rs/zerolog"
1718
flag "github.com/spf13/pflag"
1819
)
1920

21+
const (
22+
JSON = "json"
23+
TEXT = "text"
24+
CSV = "csv"
25+
)
26+
2027
type Config struct {
2128
AdditionalKinds []string
2229
AdditionalAnnotations []string
@@ -33,12 +40,14 @@ type Config struct {
3340
KubentVersion bool
3441
}
3542

36-
func NewFromFlags() (*Config, error) {
43+
func NewFromFlags(ctx context.Context) (*Config, context.Context, error) {
3744
config := Config{
3845
LogLevel: ZeroLogLevel(zerolog.InfoLevel),
3946
TargetVersion: &judge.Version{},
4047
}
4148

49+
var labels bool
50+
4251
flag.StringSliceVarP(&config.AdditionalKinds, "additional-kind", "a", []string{}, "additional kinds of resources to report in Kind.version.group.com format")
4352
flag.StringSliceVarP(&config.AdditionalAnnotations, "additional-annotation", "A", []string{}, "additional annotations that should be checked to determine the last applied config")
4453
flag.BoolVarP(&config.Cluster, "cluster", "c", true, "enable Cluster collector")
@@ -52,19 +61,22 @@ func NewFromFlags() (*Config, error) {
5261
flag.StringVarP(&config.OutputFile, "output-file", "O", "-", "output file, use - for stdout")
5362
flag.VarP(&config.LogLevel, "log-level", "l", "set log level (trace, debug, info, warn, error, fatal, panic, disabled)")
5463
flag.VarP(config.TargetVersion, "target-version", "t", "target K8s version in SemVer format (autodetected by default)")
64+
flag.BoolVar(&labels, "labels", false, "print resource labels")
5565

5666
flag.Parse()
5767

58-
if _, err := printer.ParsePrinter(config.Output); err != nil {
59-
return nil, fmt.Errorf("failed to validate argument output: %w", err)
68+
newContext := context.WithValue(ctx, ctxKey.LABELS_CTX_KEY, &labels)
69+
70+
if !isValidOutputFormat(config.Output) {
71+
return nil, nil, fmt.Errorf("failed to validate argument output: %s", config.Output)
6072
}
6173

6274
if err := validateOutputFile(config.OutputFile); err != nil {
63-
return nil, fmt.Errorf("failed to validate argument output-file: %w", err)
75+
return nil, nil, fmt.Errorf("failed to validate argument output-file: %w", err)
6476
}
6577

6678
if err := validateAdditionalResources(config.AdditionalKinds); err != nil {
67-
return nil, fmt.Errorf("failed to validate arguments: %w", err)
79+
return nil, nil, fmt.Errorf("failed to validate arguments: %w", err)
6880
}
6981

7082
// This is a little ugly, but I think preferred to implementing
@@ -74,7 +86,18 @@ func NewFromFlags() (*Config, error) {
7486
config.TargetVersion = nil
7587
}
7688

77-
return &config, nil
89+
return &config, newContext, nil
90+
}
91+
92+
// Previuosly this was handled by a printer.go ParsePrinter function
93+
// but we need to avoid cycle imports in order to inject the additional flags
94+
func isValidOutputFormat(format string) bool {
95+
switch format {
96+
case JSON, TEXT, CSV:
97+
return true
98+
default:
99+
return false
100+
}
78101
}
79102

80103
// validateAdditionalResources check that all resources are provided in full form

pkg/config/config_test.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
package config
22

33
import (
4-
goversion "github.com/hashicorp/go-version"
4+
"context"
55
"os"
66
"testing"
77

8+
goversion "github.com/hashicorp/go-version"
9+
810
"github.com/spf13/pflag"
911
)
1012

1113
func TestValidLogLevelFromFlags(t *testing.T) {
1214
oldArgs := os.Args[1]
1315
defer func() { os.Args[1] = oldArgs }()
16+
ctx := context.Background()
1417

1518
var validLevels = []string{"trace", "debug", "info", "warn", "error", "fatal", "panic", "", "disabled"}
1619
for i, level := range validLevels {
1720
// reset for testing
1821
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
1922

2023
os.Args[1] = "--log-level=" + level
21-
config, err := NewFromFlags()
24+
25+
config, _, err := NewFromFlags(ctx)
2226

2327
if err != nil {
2428
t.Errorf("Flags parsing failed %s", err)
@@ -44,8 +48,9 @@ func TestInvalidLogLevelFromFlags(t *testing.T) {
4448
func TestNewFromFlags(t *testing.T) {
4549
// reset for testing
4650
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
51+
ctx := context.Background()
4752

48-
config, err := NewFromFlags()
53+
config, _, err := NewFromFlags(ctx)
4954

5055
if err != nil {
5156
t.Errorf("Flags parsing failed %s", err)
@@ -72,9 +77,9 @@ func TestValidateAdditionalResources(t *testing.T) {
7277

7378
func TestValidateAdditionalResourcesFail(t *testing.T) {
7479
testCases := [][]string{
75-
[]string{"abcdef"},
76-
[]string{""},
77-
[]string{"test.v1.com"},
80+
{"abcdef"},
81+
{""},
82+
{"test.v1.com"},
7883
}
7984

8085
for _, tc := range testCases {
@@ -90,6 +95,7 @@ func TestTargetVersion(t *testing.T) {
9095
validVersions := []string{
9196
"1.16", "1.16.3", "1.2.3",
9297
}
98+
ctx := context.Background()
9399

94100
oldArgs := os.Args[1]
95101
defer func() { os.Args[1] = oldArgs }()
@@ -99,7 +105,7 @@ func TestTargetVersion(t *testing.T) {
99105
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
100106

101107
os.Args[1] = "--target-version=" + v
102-
config, err := NewFromFlags()
108+
config, _, err := NewFromFlags(ctx)
103109

104110
if err != nil {
105111
t.Errorf("Flags parsing failed %s", err)
@@ -120,7 +126,7 @@ func TestTargetVersionInvalid(t *testing.T) {
120126
invalidVersions := []string{
121127
"1.blah", "nope",
122128
}
123-
129+
ctx := context.Background()
124130
oldArgs := os.Args[1]
125131
defer func() { os.Args[1] = oldArgs }()
126132

@@ -129,7 +135,7 @@ func TestTargetVersionInvalid(t *testing.T) {
129135
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
130136

131137
os.Args[1] = "--target-version=" + v
132-
config, _ := NewFromFlags()
138+
config, _, _ := NewFromFlags(ctx)
133139

134140
if config.TargetVersion != nil {
135141
t.Errorf("expected --target-version flag parsing to fail for: %s", v)
@@ -141,7 +147,7 @@ func TestContext(t *testing.T) {
141147
validContexts := []string{
142148
"my-context",
143149
}
144-
150+
ctx := context.Background()
145151
oldArgs := os.Args[1]
146152
defer func() { os.Args[1] = oldArgs }()
147153

@@ -150,7 +156,7 @@ func TestContext(t *testing.T) {
150156
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
151157

152158
os.Args[1] = "--context=" + context
153-
config, err := NewFromFlags()
159+
config, _, err := NewFromFlags(ctx)
154160

155161
if err != nil {
156162
t.Errorf("Flags parsing failed %s", err)

pkg/context/context-keys.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package context
2+
3+
type ctxKey string
4+
5+
const LABELS_CTX_KEY ctxKey = "labels"

pkg/judge/judge.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type Result struct {
88
RuleSet string
99
ReplaceWith string
1010
Since *Version
11+
Labels map[string]interface{}
1112
}
1213

1314
type Judge interface {

pkg/judge/rego.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ func (j *RegoJudge) Eval(input []map[string]interface{}) ([]Result, error) {
6363
m["Namespace"] = "<undefined>"
6464
}
6565

66+
var labels map[string]interface{}
67+
if v, ok := m["Labels"].(map[string]interface{}); ok {
68+
labels = v
69+
} else {
70+
labels = make(map[string]interface{})
71+
}
6672
results = append(results, Result{
6773
Name: m["Name"].(string),
6874
Namespace: m["Namespace"].(string),
@@ -71,6 +77,7 @@ func (j *RegoJudge) Eval(input []map[string]interface{}) ([]Result, error) {
7177
ReplaceWith: m["ReplaceWith"].(string),
7278
RuleSet: m["RuleSet"].(string),
7379
Since: since,
80+
Labels: labels,
7481
})
7582
}
7683
}

0 commit comments

Comments
 (0)