Skip to content

Commit

Permalink
centralize the kustomize walking logic, upgrade linting
Browse files Browse the repository at this point in the history
  • Loading branch information
djeebus committed Jan 29, 2025
1 parent 9b88633 commit 8bfbade
Show file tree
Hide file tree
Showing 15 changed files with 372 additions and 319 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dotenv_if_exists
16 changes: 16 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
run:
tests: false

linters:
enable:
- bodyclose
- durationcheck
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unparam
- unused
- usestdlibvars
- usetesting
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
earthly 0.8.15
golang 1.22.7
golangci-lint 1.62.2
golangci-lint 1.63.4
helm 3.16.3
helm-cr 1.6.1
helm-ct 3.11.0
Expand Down
11 changes: 9 additions & 2 deletions pkg/appdir/vcstoargomap.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/rs/zerolog/log"
"github.com/zapier/kubechecks/pkg"
"github.com/zapier/kubechecks/pkg/kustomize"
)

type VcsToArgoMap struct {
Expand Down Expand Up @@ -60,7 +61,7 @@ func (v2a VcsToArgoMap) GetAppSetsInRepo(repoCloneUrl string) *AppSetDirectory {
return appSetDir
}

func (v2a VcsToArgoMap) WalkKustomizeApps(cloneURL string, fs fs.FS) *AppDirectory {
func (v2a VcsToArgoMap) WalkKustomizeApps(cloneURL string, rootFS fs.FS) *AppDirectory {
var (
err error

Expand All @@ -71,7 +72,13 @@ func (v2a VcsToArgoMap) WalkKustomizeApps(cloneURL string, fs fs.FS) *AppDirecto

for _, app := range apps {
appPath := app.Spec.GetSource().Path
if err = walkKustomizeFiles(result, fs, app.Name, appPath); err != nil {

p := processor{
appName: app.Name,
result: result,
}

if err = kustomize.ProcessKustomizationFile(rootFS, appPath, &p); err != nil {
log.Error().Err(err).Msgf("failed to parse kustomize.yaml in %s", appPath)
}
}
Expand Down
124 changes: 11 additions & 113 deletions pkg/appdir/walk_kustomize_files.go
Original file line number Diff line number Diff line change
@@ -1,124 +1,22 @@
package appdir

import (
"io"
"io/fs"
"os"
"path/filepath"
"strings"

"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"k8s.io/apimachinery/pkg/util/yaml"
"github.com/zapier/kubechecks/pkg/kustomize"
)

type patchJson6902 struct {
Path string `yaml:"path"`
type processor struct {
appName string
result *AppDirectory
}

func isGoGetterIsh(s string) bool {
if strings.HasPrefix(s, "github.com/") {
return true
}

if strings.HasPrefix(s, "https://") {
return true
}

if strings.HasPrefix(s, "http://") {
return true
}

return false
func (p *processor) AddDir(dir string) error {
p.result.addDir(p.appName, dir)
return nil
}

func walkKustomizeFiles(result *AppDirectory, fs fs.FS, appName, dirpath string) error {
kustomizeFile := filepath.Join(dirpath, "kustomization.yaml")

var (
err error

kustomize struct {
Bases []string `yaml:"bases"`
Resources []string `yaml:"resources"`
PatchesJson6902 []patchJson6902 `yaml:"patchesJson6902"`
PatchesStrategicMerge []string `yaml:"patchesStrategicMerge"`
}
)

reader, err := fs.Open(kustomizeFile)
if err != nil {
if os.IsNotExist(err) {
return nil
}

return errors.Wrap(err, "failed to open file")
}

bytes, err := io.ReadAll(reader)
if err != nil {
return errors.Wrap(err, "failed to read file")
}

if err = yaml.Unmarshal(bytes, &kustomize); err != nil {
return errors.Wrap(err, "failed to unmarshal file")
}

for _, resource := range kustomize.Resources {
if isGoGetterIsh(resource) {
// no reason to walk remote files, since they can't be changed
continue
}

var relPath string
if len(resource) >= 1 && resource[0] == '/' {
relPath = resource[1:]
} else {
relPath = filepath.Join(dirpath, resource)
}

file, err := fs.Open(relPath)
if err != nil {
return errors.Wrapf(err, "failed to read %s", relPath)
}
stat, err := file.Stat()
if err != nil {
log.Warn().Err(err).Msgf("failed to stat %s", relPath)
}

if !stat.IsDir() {
result.addFile(appName, relPath)
continue
}

result.addDir(appName, relPath)
if err = walkKustomizeFiles(result, fs, appName, relPath); err != nil {
log.Warn().Err(err).Msgf("failed to read kustomize.yaml from resources in %s", relPath)
}
}

for _, basePath := range kustomize.Bases {
if isGoGetterIsh(basePath) {
// no reason to walk remote files, since they can't be changed
continue
}

relPath := filepath.Join(dirpath, basePath)
result.addDir(appName, relPath)
if err = walkKustomizeFiles(result, fs, appName, relPath); err != nil {
log.Warn().Err(err).Msgf("failed to read kustomize.yaml from bases in %s", relPath)
}
}

for _, patchFile := range kustomize.PatchesStrategicMerge {
relPath := filepath.Join(dirpath, patchFile)
result.addFile(appName, relPath)
}

for _, patch := range kustomize.PatchesJson6902 {
relPath := filepath.Join(dirpath, patch.Path)
result.addFile(appName, relPath)
}

func (p *processor) AddFile(file string) error {
p.result.addFile(p.appName, file)
return nil
}

var _ kustomize.Processor = new(processor)
49 changes: 47 additions & 2 deletions pkg/appdir/walk_kustomize_files_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package appdir

import (
"path/filepath"
"testing"
"testing/fstest"

"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zapier/kubechecks/pkg/kustomize"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -28,6 +30,11 @@ func TestKustomizeWalking(t *testing.T) {
kustomizeApp2Path = "test/app2"

fs = fstest.MapFS{
"test/base/kustomization.yaml": {
Data: toBytes(`
resources:
- base_resource.yaml`),
},
"test/app/kustomization.yaml": {
Data: toBytes(`
bases:
Expand Down Expand Up @@ -73,6 +80,7 @@ resources:
"common/overlays/prod/kustomization.yaml": {Data: toBytes("hello: world")},
"test/overlays/base/some-file1.yaml": {Data: toBytes("hello: world")},
"test/overlays/base/some-file2.yaml": {Data: toBytes("hello: world")},
"test/base/base_resource.yaml": {Data: toBytes(`hello: world`)},
}
)

Expand Down Expand Up @@ -103,10 +111,20 @@ resources:
appdir.AddApp(newApp(kustomizeApp2Name, kustomizeApp2Path, "HEAD", false, true))
appdir.AddApp(newApp(kustomizeBaseName, kustomizeBasePath, "HEAD", false, true))

err = walkKustomizeFiles(appdir, fs, kustomizeApp1Name, kustomizeApp1Path)
testProc1 := &processor{
appName: kustomizeApp1Name,
result: appdir,
}

err = kustomize.ProcessKustomizationFile(fs, filepath.Join(kustomizeApp1Path, "kustomization.yaml"), testProc1)
require.NoError(t, err)

err = walkKustomizeFiles(appdir, fs, kustomizeApp2Name, kustomizeApp2Path)
testProc2 := &processor{
appName: kustomizeApp2Name,
result: appdir,
}

err = kustomize.ProcessKustomizationFile(fs, filepath.Join(kustomizeApp2Path, "kustomization.yaml"), testProc2)
require.NoError(t, err)

assert.Equal(t, map[string][]string{
Expand Down Expand Up @@ -138,6 +156,19 @@ resources:
}, appdir.appDirs)

assert.Equal(t, map[string][]string{
"common/overlays/prod/kustomization.yaml": {
kustomizeApp1Name,
kustomizeApp2Name,
},
"test/app/kustomization.yaml": {
kustomizeApp1Name,
},
"test/app/overlays/dev/kustomization.yaml": {
kustomizeApp1Name,
},
"test/app2/kustomization.yaml": {
kustomizeApp2Name,
},
"test/app/file1.yaml": {
kustomizeApp1Name,
},
Expand All @@ -164,5 +195,19 @@ resources:
"test/app2/file1.yaml": {
kustomizeApp2Name,
},
"test/base/base_resource.yaml": {
kustomizeApp1Name,
},
"test/base/kustomization.yaml": {
kustomizeApp1Name,
},
"test/overlays/base/kustomization.yaml": {
kustomizeApp1Name,
kustomizeApp2Name,
},
"test/overlays/common/kustomization.yaml": {
kustomizeApp1Name,
kustomizeApp2Name,
},
}, appdir.appFiles)
}
67 changes: 67 additions & 0 deletions pkg/argo_client/kustomize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package argo_client

import (
"io"
"os"
"path/filepath"

"github.com/pkg/errors"
"github.com/zapier/kubechecks/pkg/kustomize"
"sigs.k8s.io/kustomize/kyaml/filesys"
)

type processor struct {
repoRoot string
tempDir string
repoFS filesys.FileSystem
}

func (p processor) AddDir(s string) error {
return nil
}

func (p processor) AddFile(relPath string) error {
absDepPath := filepath.Clean(filepath.Join(p.repoRoot, relPath))

// Get relative path from repo root
relPath, err := filepath.Rel(p.repoRoot, absDepPath)
if err != nil {
return errors.Wrapf(err, "failed to get relative path for %s", absDepPath)
}

// check if the file exists in the temp directory
// skip copying if it exists
tempPath := filepath.Join(p.tempDir, relPath)
if _, err := os.Stat(tempPath); err == nil {
return nil
}

dstdir := filepath.Dir(tempPath)
if err := os.MkdirAll(dstdir, 0o777); err != nil {
return errors.Wrap(err, "failed to make directories")
}

r, err := os.Open(absDepPath)
if err != nil {
return err
}
defer r.Close() // ignore error: file was opened read-only.

w, err := os.Create(tempPath)
if err != nil {
return err
}

defer func() {
// Report the error, if any, from Close, but do so
// only if there isn't already an outgoing error.
if c := w.Close(); err == nil {
err = c
}
}()

_, err = io.Copy(w, r)
return errors.Wrap(err, "failed to copy file")
}

var _ kustomize.Processor = new(processor)
Loading

0 comments on commit 8bfbade

Please sign in to comment.