diff --git a/cmd/kubeconform/validate.go b/cmd/kubeconform/validate.go index 8f53365..c7ff7d2 100644 --- a/cmd/kubeconform/validate.go +++ b/cmd/kubeconform/validate.go @@ -44,21 +44,19 @@ func processResults(cancel context.CancelFunc, o output.Output, validationResult return result } -func Validate(cfg config.Config, out string) int { +func Validate(cfg config.Config, out string) error { + if out != "" { - o := cfg.Stream.Error - errCode := 1 if cfg.Help { - o = cfg.Stream.Output - errCode = 0 + fmt.Fprintln(cfg.Stream.Output, out) + return nil } - fmt.Fprintln(o, out) - return errCode + return fmt.Errorf("config out is not empty") } if cfg.Version { fmt.Fprintln(cfg.Stream.Output, out) - return 0 + return nil } cpuProfileFile := os.Getenv("KUBECONFORM_CPUPROFILE_FILE") @@ -87,8 +85,7 @@ func Validate(cfg config.Config, out string) int { o, err := output.New(cfg.Stream.Output, cfg.OutputFormat, cfg.Summary, useStdin, cfg.Verbose) if err != nil { - fmt.Fprintln(cfg.Stream.Error, err) - return 1 + return fmt.Errorf("failed to get output: %s", err.Error()) } v, err := validator.New(cfg.SchemaLocations, validator.Opts{ Cache: cfg.Cache, @@ -101,8 +98,7 @@ func Validate(cfg config.Config, out string) int { IgnoreMissingSchemas: cfg.IgnoreMissingSchemas, }) if err != nil { - fmt.Fprintln(cfg.Stream.Error, err) - return 1 + return fmt.Errorf("failed to validate: %s", err.Error()) } validationResults := make(chan validator.Result) @@ -162,8 +158,8 @@ func Validate(cfg config.Config, out string) int { o.Flush() if !success { - return 1 + return fmt.Errorf("failed to process results") } - return 0 + return nil } diff --git a/main.go b/main.go index e6d2962..29e6a22 100644 --- a/main.go +++ b/main.go @@ -16,5 +16,9 @@ func main() { fmt.Fprintf(os.Stderr, "failed parsing command line: %s\n", err.Error()) os.Exit(1) } - os.Exit(kubeconform.Validate(cfg, out)) + + if err = kubeconform.Validate(cfg, out); err != nil { + fmt.Fprintf(os.Stderr, "failed validating resources: %s - %s\n", err.Error(), out) + os.Exit(1) + } } diff --git a/pkg/config/config.go b/pkg/config/config.go index 4b834d9..86837db 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -16,24 +16,24 @@ type Stream struct { } type Config struct { - Cache string - Debug bool - ExitOnError bool - Files []string - SchemaLocations []string - SkipTLS bool - SkipKinds map[string]struct{} - RejectKinds map[string]struct{} - OutputFormat string - KubernetesVersion string - NumberOfWorkers int - Summary bool - Strict bool - Verbose bool - IgnoreMissingSchemas bool - IgnoreFilenamePatterns []string - Help bool - Version bool + Cache string `yaml:"cache" json:"cache"` + Debug bool `yaml:"debug" json:"debug"` + ExitOnError bool `yaml:"exitOnError" json:"exitOnError"` + Files []string `yaml:"files" json:"files"` + Help bool `yaml:"help" json:"help"` + IgnoreFilenamePatterns []string `yaml:"ignoreFilenamePatterns" json:"ignoreFilenamePatterns"` + IgnoreMissingSchemas bool `yaml:"ignoreMissingSchemas" json:"ignoreMissingSchemas"` + KubernetesVersion string `yaml:"kubernetesVersion" json:"kubernetesVersion"` + NumberOfWorkers int `yaml:"numberOfWorkers" json:"numberOfWorkers"` + OutputFormat string `yaml:"output" json:"output"` + RejectKinds []string `yaml:"reject" json:"reject"` + SchemaLocations []string `yaml:"schemaLocations" json:"schemaLocations"` + SkipKinds []string `yaml:"skip" json:"skip"` + SkipTLS bool `yaml:"insecureSkipTLSVerify" json:"insecureSkipTLSVerify"` + Strict bool `yaml:"strict" json:"strict"` + Summary bool `yaml:"summary" json:"summary"` + Verbose bool `yaml:"verbose" json:"verbose"` + Version bool `yaml:"version" json:"version"` Stream *Stream } @@ -48,19 +48,6 @@ func (ap *arrayParam) Set(value string) error { return nil } -func splitCSV(csvStr string) map[string]struct{} { - splitValues := strings.Split(csvStr, ",") - valuesMap := map[string]struct{}{} - - for _, kind := range splitValues { - if len(kind) > 0 { - valuesMap[kind] = struct{}{} - } - } - - return valuesMap -} - // FromFlags retrieves kubeconform's runtime configuration from the command-line parameters func FromFlags(progName string, args []string) (Config, string, error) { var schemaLocationsParam, ignoreFilenamePatterns arrayParam @@ -98,8 +85,8 @@ func FromFlags(progName string, args []string) (Config, string, error) { err := flags.Parse(args) - c.SkipKinds = splitCSV(skipKindsCSV) - c.RejectKinds = splitCSV(rejectKindsCSV) + c.SkipKinds = strings.Split(skipKindsCSV, ",") + c.RejectKinds = strings.Split(rejectKindsCSV, ",") c.IgnoreFilenamePatterns = ignoreFilenamePatterns c.SchemaLocations = schemaLocationsParam c.Files = flags.Args() diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 9a184d5..7337d01 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -2,6 +2,7 @@ package config import ( "reflect" + "strings" "testing" ) @@ -33,7 +34,7 @@ func TestSkipKindMaps(t *testing.T) { }, }, } { - got := splitCSV(testCase.csvSkipKinds) + got := strings.Split(testCase.csvSkipKinds, ",") if !reflect.DeepEqual(got, testCase.expect) { t.Errorf("%s - got %+v, expected %+v", testCase.name, got, testCase.expect) } @@ -53,8 +54,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 4, OutputFormat: "text", SchemaLocations: nil, - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, }, }, { @@ -66,8 +67,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 4, OutputFormat: "text", SchemaLocations: nil, - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, }, }, { @@ -79,8 +80,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 4, OutputFormat: "text", SchemaLocations: nil, - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, }, }, { @@ -91,8 +92,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 4, OutputFormat: "text", SchemaLocations: nil, - SkipKinds: map[string]struct{}{"a": {}, "b": {}, "c": {}}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{"a", "b", "c"}, + RejectKinds: []string{}, }, }, { @@ -103,8 +104,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 4, OutputFormat: "text", SchemaLocations: nil, - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, Summary: true, Verbose: true, }, @@ -122,8 +123,8 @@ func TestFromFlags(t *testing.T) { NumberOfWorkers: 2, OutputFormat: "json", SchemaLocations: []string{"folder", "anotherfolder"}, - SkipKinds: map[string]struct{}{"kinda": {}, "kindb": {}}, - RejectKinds: map[string]struct{}{"kindc": {}, "kindd": {}}, + SkipKinds: []string{"kinda", "kindb"}, + RejectKinds: []string{"kindc", "kindd"}, Strict: true, Summary: true, Verbose: true, diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go new file mode 100644 index 0000000..a002352 --- /dev/null +++ b/pkg/utils/utils.go @@ -0,0 +1,12 @@ +package utils + +// Check if element is in an array. +func InArray(arr []string, str string) bool { + for _, elem := range arr { + if elem == str { + return true + } + } + + return false +} diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index f4827c8..d177120 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -12,6 +12,7 @@ import ( "github.com/yannh/kubeconform/pkg/cache" "github.com/yannh/kubeconform/pkg/registry" "github.com/yannh/kubeconform/pkg/resource" + "github.com/yannh/kubeconform/pkg/utils" "sigs.k8s.io/yaml" ) @@ -53,14 +54,14 @@ type Validator interface { // Opts contains a set of options for the validator. type Opts struct { - Cache string // Cache schemas downloaded via HTTP to this folder - Debug bool // Debug infos will be print here - SkipTLS bool // skip TLS validation when downloading from an HTTP Schema Registry - SkipKinds map[string]struct{} // List of resource Kinds to ignore - RejectKinds map[string]struct{} // List of resource Kinds to reject - KubernetesVersion string // Kubernetes Version - has to match one in https://github.com/instrumenta/kubernetes-json-schema - Strict bool // thros an error if resources contain undocumented fields - IgnoreMissingSchemas bool // skip a resource if no schema for that resource can be found + Cache string // Cache schemas downloaded via HTTP to this folder + Debug bool // Debug infos will be print here + SkipTLS bool // skip TLS validation when downloading from an HTTP Schema Registry + SkipKinds []string // List of resource Kinds to ignore + RejectKinds []string // List of resource Kinds to reject + KubernetesVersion string // Kubernetes Version - has to match one in https://github.com/instrumenta/kubernetes-json-schema + Strict bool // thros an error if resources contain undocumented fields + IgnoreMissingSchemas bool // skip a resource if no schema for that resource can be found } // New returns a new Validator @@ -85,10 +86,10 @@ func New(schemaLocations []string, opts Opts) (Validator, error) { } if opts.SkipKinds == nil { - opts.SkipKinds = map[string]struct{}{} + opts.SkipKinds = []string{} } if opts.RejectKinds == nil { - opts.RejectKinds = map[string]struct{}{} + opts.RejectKinds = []string{} } return &v{ @@ -115,19 +116,17 @@ func (val *v) ValidateResource(res resource.Resource) Result { // for skipping/rejecting resources) and the raw Kind. skip := func(signature resource.Signature) bool { - if _, ok := val.opts.SkipKinds[signature.GroupVersionKind()]; ok { + if ok := utils.InArray(val.opts.SkipKinds, signature.GroupVersionKind()); ok { return ok } - _, ok := val.opts.SkipKinds[signature.Kind] - return ok + return utils.InArray(val.opts.SkipKinds, signature.Kind) } reject := func(signature resource.Signature) bool { - if _, ok := val.opts.RejectKinds[signature.GroupVersionKind()]; ok { + if ok := utils.InArray(val.opts.RejectKinds, signature.GroupVersionKind()); ok { return ok } - _, ok := val.opts.RejectKinds[signature.Kind] - return ok + return utils.InArray(val.opts.RejectKinds, signature.Kind) } if len(res.Bytes) == 0 { diff --git a/pkg/validator/validator_test.go b/pkg/validator/validator_test.go index 0776253..bc7d727 100644 --- a/pkg/validator/validator_test.go +++ b/pkg/validator/validator_test.go @@ -355,8 +355,8 @@ lastName: bar } { val := v{ opts: Opts{ - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, IgnoreMissingSchemas: testCase.ignoreMissingSchema, Strict: testCase.strict, }, @@ -418,8 +418,8 @@ age: not a number val := v{ opts: Opts{ - SkipKinds: map[string]struct{}{}, - RejectKinds: map[string]struct{}{}, + SkipKinds: []string{}, + RejectKinds: []string{}, }, schemaCache: nil, schemaDownload: downloadSchema,