Skip to content

Commit

Permalink
Add CreateContextsFromHelmArchive for improved support of kube-linter…
Browse files Browse the repository at this point in the history
… as a library (#173)
  • Loading branch information
slysunkin authored May 7, 2021
1 parent d589da4 commit 622c0b5
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 19 deletions.
11 changes: 11 additions & 0 deletions pkg/lintcontext/create_contexts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lintcontext

import (
"io"
"os"
"path/filepath"
"sort"
Expand Down Expand Up @@ -112,3 +113,13 @@ func CreateContextsWithOptions(options Options, filesOrDirs ...string) ([]LintCo
}
return contexts, nil
}

// CreateContextsFromHelmArchive creates a context from TGZ reader of Helm Chart.
func CreateContextsFromHelmArchive(fileName string, tgzReader io.Reader) ([]LintContext, error) {
ctx := newCtx(Options{})
if err := ctx.readObjectsFromTgzHelmChart(fileName, tgzReader); err != nil {
return nil, err
}

return []LintContext{ctx}, nil
}
27 changes: 27 additions & 0 deletions pkg/lintcontext/create_contexts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lintcontext

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCreateContextsFromHelmArchive(t *testing.T) {
fileName := "../../tests/testdata/mychart-0.1.0.tgz"
file, err := os.Open(fileName)
require.NoError(t, err)

lintCtxs, err := CreateContextsFromHelmArchive("test", file)
assert.NoError(t, err)

var atLeastOneObjectFound bool
for _, lintCtx := range lintCtxs {
if len(lintCtx.Objects()) > 0 {
atLeastOneObjectFound = true
break
}
}
assert.True(t, atLeastOneObjectFound, "no valid objects found")
}
75 changes: 56 additions & 19 deletions pkg/lintcontext/parse_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,25 +167,7 @@ func (l *lintContextImpl) renderTgzHelmChart(tgzFile string) (map[string]string,
return nil, err
}

valuesIndex := -1
for i, f := range chrt.Raw {
if f.Name == "values.yaml" {
valuesIndex = i
break
}
}

indexName := filepath.Join(tgzFile, "values.yaml")
if valuesIndex == -1 {
return nil, errors.Errorf("%s not found", indexName)
}

values, err := l.parseValues(indexName, chrt.Raw[valuesIndex].Data)
if err != nil {
return nil, errors.Wrap(err, "loading values.yaml file")
}

return l.renderValues(chrt, values)
return l.renderChart(tgzFile, chrt)
}

func (l *lintContextImpl) parseValues(filePath string, bytes []byte) (map[string]interface{}, error) {
Expand Down Expand Up @@ -256,3 +238,58 @@ func (l *lintContextImpl) loadObjectsFromReader(filePath string, reader io.Reade
}
}
}

func (l *lintContextImpl) renderChart(fileName string, chart *chart.Chart) (map[string]string, error) {
if err := chart.Validate(); err != nil {
return nil, err
}

valuesIndex := -1
for i, f := range chart.Raw {
if f.Name == "values.yaml" {
valuesIndex = i
break
}
}

indexName := filepath.Join(fileName, "values.yaml")
if valuesIndex == -1 {
return nil, errors.Errorf("%s not found", indexName)
}

values, err := l.parseValues(indexName, chart.Raw[valuesIndex].Data)
if err != nil {
return nil, errors.Wrap(err, "loading values.yaml file")
}

return l.renderValues(chart, values)
}

func (l *lintContextImpl) renderTgzHelmChartReader(fileName string, tgzReader io.Reader) (map[string]string, error) {
// Helm doesn't have great logging behaviour, and can spam stderr, so silence their logging.
log.SetOutput(nopWriter{})
defer log.SetOutput(os.Stderr)
chrt, err := loader.LoadArchive(tgzReader)

if err != nil {
return nil, err
}

return l.renderChart(fileName, chrt)
}

func (l *lintContextImpl) readObjectsFromTgzHelmChart(fileName string, tgzReader io.Reader) error {
metadata := ObjectMetadata{FilePath: fileName}
renderedFiles, err := l.renderTgzHelmChartReader(fileName, tgzReader)
if err != nil {
l.invalidObjects = append(l.invalidObjects, InvalidObject{Metadata: metadata, LoadErr: err})
return nil
}
for path, contents := range renderedFiles {
pathToTemplate := filepath.Join(fileName, path)
if err := l.loadObjectsFromReader(pathToTemplate, strings.NewReader(contents)); err != nil {
return errors.Wrapf(err, "loading objects from rendered helm chart %s", pathToTemplate)
}
}
return nil
}
Binary file added tests/testdata/mychart-0.1.0.tgz
Binary file not shown.

0 comments on commit 622c0b5

Please sign in to comment.