add kustomizationVisitor type and use it when kustomization is enabled

This commit is contained in:
Jingfang Liu 2018-12-12 09:41:42 -08:00
parent 5604a15024
commit 26c07715c7
3 changed files with 63 additions and 8 deletions

View File

@ -35,12 +35,16 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps:go_default_library",
"//staging/src/k8s.io/client-go/discovery:go_default_library", "//staging/src/k8s.io/client-go/discovery:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/restmapper:go_default_library", "//staging/src/k8s.io/client-go/restmapper:go_default_library",
"//vendor/golang.org/x/text/encoding/unicode:go_default_library", "//vendor/golang.org/x/text/encoding/unicode:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library", "//vendor/golang.org/x/text/transform:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/commands/build:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/constants:go_default_library",
"//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library",
], ],
) )

View File

@ -130,8 +130,9 @@ func IsUsageError(err error) bool {
} }
type FilenameOptions struct { type FilenameOptions struct {
Filenames []string Filenames []string
Recursive bool Recursive bool
EnableKustomization bool
} }
type resourceTuple struct { type resourceTuple struct {
@ -197,6 +198,7 @@ func (b *Builder) AddError(err error) *Builder {
// recognized will be ignored (but logged at V(2)). // recognized will be ignored (but logged at V(2)).
func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *FilenameOptions) *Builder { func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *FilenameOptions) *Builder {
recursive := filenameOptions.Recursive recursive := filenameOptions.Recursive
enableKustomization := filenameOptions.EnableKustomization
paths := filenameOptions.Filenames paths := filenameOptions.Filenames
for _, s := range paths { for _, s := range paths {
switch { switch {
@ -213,7 +215,7 @@ func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *Filename
if !recursive { if !recursive {
b.singleItemImplied = true b.singleItemImplied = true
} }
b.Path(recursive, s) b.Path(recursive, enableKustomization, s)
} }
} }
@ -332,7 +334,7 @@ func (b *Builder) Stream(r io.Reader, name string) *Builder {
// FileVisitor is streaming the content to a StreamVisitor. If ContinueOnError() is set // FileVisitor is streaming the content to a StreamVisitor. If ContinueOnError() is set
// prior to this method being called, objects on the path that are unrecognized will be // prior to this method being called, objects on the path that are unrecognized will be
// ignored (but logged at V(2)). // ignored (but logged at V(2)).
func (b *Builder) Path(recursive bool, paths ...string) *Builder { func (b *Builder) Path(recursive, enableKustomization bool, paths ...string) *Builder {
for _, p := range paths { for _, p := range paths {
_, err := os.Stat(p) _, err := os.Stat(p)
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -344,7 +346,7 @@ func (b *Builder) Path(recursive bool, paths ...string) *Builder {
continue continue
} }
visitors, err := ExpandPathsToFileVisitors(b.mapper, p, recursive, FileExtensions, b.schema) visitors, err := ExpandPathsToFileVisitors(b.mapper, p, recursive, enableKustomization, FileExtensions, b.schema)
if err != nil { if err != nil {
b.errs = append(b.errs, fmt.Errorf("error reading %q: %v", p, err)) b.errs = append(b.errs, fmt.Errorf("error reading %q: %v", p, err))
} }

View File

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -38,6 +39,10 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/yaml" "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/kustomize/k8sdeps"
"sigs.k8s.io/kustomize/pkg/commands/build"
"sigs.k8s.io/kustomize/pkg/constants"
"sigs.k8s.io/kustomize/pkg/fs"
) )
const ( const (
@ -446,13 +451,16 @@ func FileVisitorForSTDIN(mapper *mapper, schema ContentValidator) Visitor {
// ExpandPathsToFileVisitors will return a slice of FileVisitors that will handle files from the provided path. // ExpandPathsToFileVisitors will return a slice of FileVisitors that will handle files from the provided path.
// After FileVisitors open the files, they will pass an io.Reader to a StreamVisitor to do the reading. (stdin // After FileVisitors open the files, they will pass an io.Reader to a StreamVisitor to do the reading. (stdin
// is also taken care of). Paths argument also accepts a single file, and will return a single visitor // is also taken care of). Paths argument also accepts a single file, and will return a single visitor
func ExpandPathsToFileVisitors(mapper *mapper, paths string, recursive bool, extensions []string, schema ContentValidator) ([]Visitor, error) { func ExpandPathsToFileVisitors(mapper *mapper, paths string, recursive bool, enableKustomize bool, extensions []string, schema ContentValidator) ([]Visitor, error) {
var visitors []Visitor var visitors []Visitor
err := filepath.Walk(paths, func(path string, fi os.FileInfo, err error) error { err := filepath.Walk(paths, func(path string, fi os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if enableKustomize && isKustomizationDir(path) {
visitors = append(visitors, NewKustomizationVisitor(mapper, path, schema))
return filepath.SkipDir
}
if fi.IsDir() { if fi.IsDir() {
if path != paths && !recursive { if path != paths && !recursive {
return filepath.SkipDir return filepath.SkipDir
@ -463,7 +471,10 @@ func ExpandPathsToFileVisitors(mapper *mapper, paths string, recursive bool, ext
if path != paths && ignoreFile(path, extensions) { if path != paths && ignoreFile(path, extensions) {
return nil return nil
} }
if enableKustomize && filepath.Base(path) == constants.KustomizationFileName {
visitors = append(visitors, NewKustomizationVisitor(mapper, filepath.Dir(path), schema))
return nil
}
visitor := &FileVisitor{ visitor := &FileVisitor{
Path: path, Path: path,
StreamVisitor: NewStreamVisitor(nil, mapper, path, schema), StreamVisitor: NewStreamVisitor(nil, mapper, path, schema),
@ -479,6 +490,13 @@ func ExpandPathsToFileVisitors(mapper *mapper, paths string, recursive bool, ext
return visitors, nil return visitors, nil
} }
func isKustomizationDir(path string) bool {
if _, err := os.Stat(filepath.Join(path, constants.KustomizationFileName)); err == nil {
return true
}
return false
}
// FileVisitor is wrapping around a StreamVisitor, to handle open/close files // FileVisitor is wrapping around a StreamVisitor, to handle open/close files
type FileVisitor struct { type FileVisitor struct {
Path string Path string
@ -507,6 +525,37 @@ func (v *FileVisitor) Visit(fn VisitorFunc) error {
return v.StreamVisitor.Visit(fn) return v.StreamVisitor.Visit(fn)
} }
// KustomizationVisitor prorvides the output of kustomization build
type KustomizationVisitor struct {
Path string
*StreamVisitor
}
// Visit in a KustomizationVisitor build the kustomization output
func (v *KustomizationVisitor) Visit(fn VisitorFunc) error {
fSys := fs.MakeRealFS()
f := k8sdeps.NewFactory()
var out bytes.Buffer
cmd := build.NewCmdBuild(&out, fSys, f.ResmapF, f.TransformerF)
cmd.SetArgs([]string{v.Path})
// we want to silence usage, error output, and any future output from cobra
// we will get error output as a golang error from execute
cmd.SetOutput(ioutil.Discard)
_, err := cmd.ExecuteC()
if err != nil {
return err
}
v.StreamVisitor.Reader = bytes.NewReader(out.Bytes())
return v.StreamVisitor.Visit(fn)
}
func NewKustomizationVisitor(mapper *mapper, path string, schema ContentValidator) *KustomizationVisitor {
return &KustomizationVisitor{
Path: path,
StreamVisitor: NewStreamVisitor(nil, mapper, path, schema),
}
}
// StreamVisitor reads objects from an io.Reader and walks them. A stream visitor can only be // StreamVisitor reads objects from an io.Reader and walks them. A stream visitor can only be
// visited once. // visited once.
// TODO: depends on objects being in JSON format before being passed to decode - need to implement // TODO: depends on objects being in JSON format before being passed to decode - need to implement