From 244a1733c8002eff787baa8d122755c9a7611e7c Mon Sep 17 00:00:00 2001 From: Arvind Iyengar Date: Fri, 26 Mar 2021 18:07:38 -0700 Subject: [PATCH 1/2] Add CreateContextWithOptions for lintcontext Allows users to provide options for creating lint context. Related Issue: https://github.com/stackrox/kube-linter/issues/141 Signed-off-by: Arvind Iyengar --- pkg/lintcontext/context.go | 3 +++ pkg/lintcontext/create_contexts.go | 16 ++++++++++++++++ pkg/lintcontext/parse_yaml.go | 12 ++++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/pkg/lintcontext/context.go b/pkg/lintcontext/context.go index fb13d99c9..ebfccae0b 100644 --- a/pkg/lintcontext/context.go +++ b/pkg/lintcontext/context.go @@ -2,6 +2,7 @@ package lintcontext import ( "golang.stackrox.io/kube-linter/internal/k8sutil" + "k8s.io/apimachinery/pkg/runtime" ) // ObjectMetadata is metadata about an object. @@ -31,6 +32,8 @@ type LintContext interface { type lintContextImpl struct { objects []Object invalidObjects []InvalidObject + + customDecoder runtime.Decoder } // Objects returns the (valid) objects loaded from this LintContext. diff --git a/pkg/lintcontext/create_contexts.go b/pkg/lintcontext/create_contexts.go index b9f8146c7..389481ca0 100644 --- a/pkg/lintcontext/create_contexts.go +++ b/pkg/lintcontext/create_contexts.go @@ -9,19 +9,31 @@ import ( "github.com/pkg/errors" "golang.stackrox.io/kube-linter/internal/set" "helm.sh/helm/v3/pkg/chartutil" + "k8s.io/apimachinery/pkg/runtime" ) var ( knownYAMLExtensions = set.NewFrozenStringSet(".yaml", ".yml") ) +// Options represent values that can be provided to modify how objects are parsed to create lint contexts +type Options struct { + // CustomDecoder allows users to supply a non-default decoder to parse k8s objects. This can be used + // to allow the linter to create contexts for k8s custom resources + CustomDecoder runtime.Decoder +} + // CreateContexts creates a context. Each context contains a set of files that should be linted // as a group. // Currently, each directory of Kube YAML files (or Helm charts) are treated as a separate context. // TODO: Figure out if it's useful to allow people to specify that files spanning different directories // should be treated as being in the same context. func CreateContexts(filesOrDirs ...string) ([]LintContext, error) { + return CreateContextsWithOptions(Options{}, filesOrDirs...) +} +// CreateContextsWithOptions creates a context with additional Options +func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintContext, error) { contextsByDir := make(map[string]*lintContextImpl) for _, fileOrDir := range filesOrDirs { // Stdin @@ -30,6 +42,7 @@ func CreateContexts(filesOrDirs ...string) ([]LintContext, error) { continue } ctx := new() + ctx.customDecoder = options.CustomDecoder if err := ctx.loadObjectsFromReader("", os.Stdin); err != nil { return nil, err } @@ -49,6 +62,7 @@ func CreateContexts(filesOrDirs ...string) ([]LintContext, error) { if !info.IsDir() { if strings.HasSuffix(strings.ToLower(currentPath), ".tgz") { ctx := new() + ctx.customDecoder = options.CustomDecoder if err := ctx.loadObjectsFromTgzHelmChart(currentPath); err != nil { return err } @@ -63,6 +77,7 @@ func CreateContexts(filesOrDirs ...string) ([]LintContext, error) { ctx := contextsByDir[dirName] if ctx == nil { ctx = new() + ctx.customDecoder = options.CustomDecoder contextsByDir[dirName] = ctx } if err := ctx.loadObjectsFromYAMLFile(currentPath, info); err != nil { @@ -77,6 +92,7 @@ func CreateContexts(filesOrDirs ...string) ([]LintContext, error) { return nil } ctx := new() + ctx.customDecoder = options.CustomDecoder contextsByDir[currentPath] = ctx if err := ctx.loadObjectsFromHelmChart(currentPath); err != nil { return err diff --git a/pkg/lintcontext/parse_yaml.go b/pkg/lintcontext/parse_yaml.go index 63b5e1e0e..e71bf6f7e 100644 --- a/pkg/lintcontext/parse_yaml.go +++ b/pkg/lintcontext/parse_yaml.go @@ -18,6 +18,7 @@ import ( "helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v3/pkg/engine" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes/scheme" @@ -34,15 +35,18 @@ var ( decoder = serializer.NewCodecFactory(clientSchema).UniversalDeserializer() ) -func parseObjects(data []byte) ([]k8sutil.Object, error) { - obj, _, err := decoder.Decode(data, nil, nil) +func parseObjects(data []byte, d runtime.Decoder) ([]k8sutil.Object, error) { + if d == nil { + d = decoder + } + obj, _, err := d.Decode(data, nil, nil) if err != nil { return nil, errors.Wrap(err, "failed to decode") } if list, ok := obj.(*v1.List); ok { objs := make([]k8sutil.Object, 0, len(list.Items)) for i, item := range list.Items { - obj, _, err := decoder.Decode(item.Raw, nil, nil) + obj, _, err := d.Decode(item.Raw, nil, nil) if err != nil { return nil, errors.Wrapf(err, "decoding item %d in the list", i) } @@ -197,7 +201,7 @@ func (l *lintContextImpl) loadObjectFromYAMLReader(filePath string, r *yaml.YAML Raw: doc, } - objs, err := parseObjects(doc) + objs, err := parseObjects(doc, l.customDecoder) if err != nil { l.addInvalidObjects(InvalidObject{ Metadata: metadata, From 6c8a7b740e473a8866ba668b29b4b7c7383cc3e5 Mon Sep 17 00:00:00 2001 From: Arvind Iyengar Date: Sat, 27 Mar 2021 17:59:49 -0700 Subject: [PATCH 2/2] Switch new to newCtx(options Options) Signed-off-by: Arvind Iyengar --- pkg/lintcontext/context.go | 6 ++++-- pkg/lintcontext/create_contexts.go | 12 ++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/pkg/lintcontext/context.go b/pkg/lintcontext/context.go index ebfccae0b..e6bb24e98 100644 --- a/pkg/lintcontext/context.go +++ b/pkg/lintcontext/context.go @@ -57,6 +57,8 @@ func (l *lintContextImpl) addInvalidObjects(objs ...InvalidObject) { } // new returns a ready-to-use, empty, lintContextImpl. -func new() *lintContextImpl { - return &lintContextImpl{} +func newCtx(options Options) *lintContextImpl { + return &lintContextImpl{ + customDecoder: options.CustomDecoder, + } } diff --git a/pkg/lintcontext/create_contexts.go b/pkg/lintcontext/create_contexts.go index 389481ca0..43a08f425 100644 --- a/pkg/lintcontext/create_contexts.go +++ b/pkg/lintcontext/create_contexts.go @@ -41,8 +41,7 @@ func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintCo if _, alreadyExists := contextsByDir["-"]; alreadyExists { continue } - ctx := new() - ctx.customDecoder = options.CustomDecoder + ctx := newCtx(options) if err := ctx.loadObjectsFromReader("", os.Stdin); err != nil { return nil, err } @@ -61,8 +60,7 @@ func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintCo if !info.IsDir() { if strings.HasSuffix(strings.ToLower(currentPath), ".tgz") { - ctx := new() - ctx.customDecoder = options.CustomDecoder + ctx := newCtx(options) if err := ctx.loadObjectsFromTgzHelmChart(currentPath); err != nil { return err } @@ -76,8 +74,7 @@ func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintCo if knownYAMLExtensions.Contains(strings.ToLower(filepath.Ext(currentPath))) || fileOrDir == currentPath { ctx := contextsByDir[dirName] if ctx == nil { - ctx = new() - ctx.customDecoder = options.CustomDecoder + ctx = newCtx(options) contextsByDir[dirName] = ctx } if err := ctx.loadObjectsFromYAMLFile(currentPath, info); err != nil { @@ -91,8 +88,7 @@ func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintCo if _, alreadyExists := contextsByDir[currentPath]; alreadyExists { return nil } - ctx := new() - ctx.customDecoder = options.CustomDecoder + ctx := newCtx(options) contextsByDir[currentPath] = ctx if err := ctx.loadObjectsFromHelmChart(currentPath); err != nil { return err