Compare commits

..

1 Commits

Author SHA1 Message Date
jingfangliu
9b3a0c971a update client-go version 2019-08-15 16:55:44 -07:00
549 changed files with 9465 additions and 40942 deletions

View File

@@ -1,11 +1,7 @@
os:
- linux
# TODO: Uncomment this when someone figures out how
# to speed up the slowness of homebrew installation on
# oxs; presumably cache images?
# - osx
#
# TODO: Uncomment when some gets the tests running on Windows.
- osx
# TODO: Uncomment when tests running on Windows.
# - windows
addons:
@@ -24,12 +20,18 @@ git:
language: go
go:
- "1.13"
- "1.12"
go_import_path: sigs.k8s.io/kustomize
before_install:
- source ./travis/consider-early-travis-exit.sh
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.17.1
- go get -u github.com/monopole/mdrip
# The following would install Helm if needed for some reason.
# - wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
# - tar -xvzf helm-v2.13.1-linux-amd64.tar.gz
# - sudo mv linux-amd64/helm /usr/local/bin/helm
# Skip the install process; let pre-commit.sh do it.
install: true

View File

@@ -1,37 +0,0 @@
BIN_NAME=kustomize
COVER_FILE=coverage.out
export GO111MODULE=on
all: test build
test: generate-code test-lint test-go
test-go:
go test -v ./...
test-lint:
golangci-lint run ./...
generate-code:
./plugin/generateBuiltins.sh $(GOPATH)
build:
go build -o $(BIN_NAME) cmd/kustomize/main.go
install:
go install $(PWD)/cmd/kustomize
cover:
# The plugin directory eludes coverage, and is therefore omitted
go test ./pkg/... ./k8sdeps/... ./internal/... -coverprofile=$(COVER_FILE) && \
go tool cover -html=$(COVER_FILE)
clean:
go clean
rm -f $(BIN_NAME)
rm -f $(COVER_FILE)
.PHONY: test build install clean generate-code test-go test-lint cover

View File

@@ -22,17 +22,8 @@ these [instructions](docs/INSTALL.md).
Browse the [docs](docs) or jump right into the
tested [examples](examples).
## kubectl integration
kustomize [v2.0.3] is available in [kubectl v1.15][kubectl].
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
| kubectl version | kustomize version |
|---------|--------|
| v1.16.0 | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
| v1.15.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
| v1.14.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
## Usage
@@ -168,9 +159,7 @@ is governed by the [Kubernetes Code of Conduct].
[imageBase]: docs/images/base.jpg
[imageOverlay]: docs/images/overlay.jpg
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/labels/kind%2Ffeature
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
[kubectl]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
[kubernetes style]: docs/glossary.md#kubernetes-style-object
[kustomization]: docs/glossary.md#kustomization
[overlay]: docs/glossary.md#overlay

View File

@@ -1,41 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"io"
"os"
"time"
)
var _ os.FileInfo = &fileInfo{}
// fileInfo implements os.FileInfo for a fileInMemory instance.
type fileInfo struct {
*fileInMemory
}
// Name returns the name of the file
func (fi *fileInfo) Name() string { return fi.name }
// Size returns the size of the file
func (fi *fileInfo) Size() int64 { return int64(len(fi.content)) }
// Mode returns the file mode
func (fi *fileInfo) Mode() os.FileMode { return 0777 }
// ModTime returns the modification time
func (fi *fileInfo) ModTime() time.Time { return time.Time{} }
// IsDir returns if it is a directory
func (fi *fileInfo) IsDir() bool { return fi.dir }
// Sys should return underlying data source, but it now returns nil
func (fi *fileInfo) Sys() interface{} { return nil }
// File groups the basic os.File methods.
type File interface {
io.ReadWriteCloser
Stat() (os.FileInfo, error)
}

View File

@@ -1,56 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"bytes"
"os"
)
var _ File = &fileInMemory{}
// fileInMemory implements File in-memory for tests.
type fileInMemory struct {
name string
content []byte
dir bool
open bool
}
// makeDir makes a fake directory.
func makeDir(name string) *fileInMemory {
return &fileInMemory{name: name, dir: true}
}
// Close marks the fake file closed.
func (f *fileInMemory) Close() error {
f.open = false
return nil
}
// Read never fails, and doesn't mutate p.
func (f *fileInMemory) Read(p []byte) (n int, err error) {
return len(p), nil
}
// Write saves the contents of the argument to memory.
func (f *fileInMemory) Write(p []byte) (n int, err error) {
f.content = p
return len(p), nil
}
// ContentMatches returns true if v matches fake file's content.
func (f *fileInMemory) ContentMatches(v []byte) bool {
return bytes.Equal(v, f.content)
}
// GetContent the content of a fake file.
func (f *fileInMemory) GetContent() []byte {
return f.content
}
// Stat returns nil.
func (f *fileInMemory) Stat() (os.FileInfo, error) {
return nil, nil
}

View File

@@ -1,27 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"os"
)
var _ File = &fileOnDisk{}
// fileOnDisk implements File using the local filesystem.
type fileOnDisk struct {
file *os.File
}
// Close closes a file.
func (f *fileOnDisk) Close() error { return f.file.Close() }
// Read reads a file's content.
func (f *fileOnDisk) Read(p []byte) (n int, err error) { return f.file.Read(p) }
// Write writes bytes to a file
func (f *fileOnDisk) Write(p []byte) (n int, err error) { return f.file.Write(p) }
// Stat returns an interface which has all the information regarding the file.
func (f *fileOnDisk) Stat() (os.FileInfo, error) { return f.file.Stat() }

View File

@@ -1,41 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package filesys provides a file system abstraction layer.
package filesys
import (
"path/filepath"
)
// FileSystem groups basic os filesystem methods.
type FileSystem interface {
// Create a file.
Create(name string) (File, error)
// MkDir makes a directory.
Mkdir(path string) error
// MkDir makes a directory path, creating intervening directories.
MkdirAll(path string) error
// RemoveAll removes path and any children it contains.
RemoveAll(path string) error
// Open opens the named file for reading.
Open(path string) (File, error)
// IsDir returns true if the path is a directory.
IsDir(path string) bool
// CleanedAbs converts the given path into a
// directory and a file name, where the directory
// is represented as a ConfirmedDir and all that implies.
// If the entire path is a directory, the file component
// is an empty string.
CleanedAbs(path string) (ConfirmedDir, string, error)
// Exists is true if the path exists in the file system.
Exists(path string) bool
// Glob returns the list of matching files
Glob(pattern string) ([]string, error)
// ReadFile returns the contents of the file at the given path.
ReadFile(path string) ([]byte, error)
// WriteFile writes the data to a file at the given path.
WriteFile(path string, data []byte) error
// Walk walks the file system with the given WalkFunc.
Walk(path string, walkFn filepath.WalkFunc) error
}

View File

@@ -1,223 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
)
var _ FileSystem = &fsInMemory{}
// fsInMemory implements FileSystem using a in-memory filesystem
// primarily for use in tests.
type fsInMemory struct {
m map[string]*fileInMemory
}
// MakeFsInMemory returns an instance of fsInMemory with no files in it.
func MakeFsInMemory() FileSystem {
result := &fsInMemory{m: map[string]*fileInMemory{}}
result.Mkdir(separator)
return result
}
const (
separator = string(filepath.Separator)
doubleSep = separator + separator
)
// Create assures a fake file appears in the in-memory file system.
func (fs *fsInMemory) Create(name string) (File, error) {
f := &fileInMemory{}
f.open = true
fs.m[name] = f
return fs.m[name], nil
}
// Mkdir assures a fake directory appears in the in-memory file system.
func (fs *fsInMemory) Mkdir(name string) error {
fs.m[name] = makeDir(name)
return nil
}
// MkdirAll delegates to Mkdir
func (fs *fsInMemory) MkdirAll(name string) error {
return fs.Mkdir(name)
}
// RemoveAll presumably does rm -r on a path.
// There's no error.
func (fs *fsInMemory) RemoveAll(name string) error {
var toRemove []string
for k := range fs.m {
if strings.HasPrefix(k, name) {
toRemove = append(toRemove, k)
}
}
for _, k := range toRemove {
delete(fs.m, k)
}
return nil
}
// Open returns a fake file in the open state.
func (fs *fsInMemory) Open(name string) (File, error) {
if _, found := fs.m[name]; !found {
return nil, fmt.Errorf("file %q cannot be opened", name)
}
return fs.m[name], nil
}
// CleanedAbs cannot fail.
func (fs *fsInMemory) CleanedAbs(path string) (ConfirmedDir, string, error) {
if fs.IsDir(path) {
return ConfirmedDir(path), "", nil
}
d := filepath.Dir(path)
if d == path {
return ConfirmedDir(d), "", nil
}
return ConfirmedDir(d), filepath.Base(path), nil
}
// Exists returns true if file is known.
func (fs *fsInMemory) Exists(name string) bool {
_, found := fs.m[name]
return found
}
// Glob returns the list of matching files
func (fs *fsInMemory) Glob(pattern string) ([]string, error) {
var result []string
for p := range fs.m {
if fs.pathMatch(p, pattern) {
result = append(result, p)
}
}
sort.Strings(result)
return result, nil
}
// IsDir returns true if the file exists and is a directory.
func (fs *fsInMemory) IsDir(name string) bool {
f, found := fs.m[name]
if found && f.dir {
return true
}
if !strings.HasSuffix(name, separator) {
name = name + separator
}
for k := range fs.m {
if strings.HasPrefix(k, name) {
return true
}
}
return false
}
// ReadFile always returns an empty bytes and error depending on content of m.
func (fs *fsInMemory) ReadFile(name string) ([]byte, error) {
if ff, found := fs.m[name]; found {
return ff.content, nil
}
return nil, fmt.Errorf("cannot read file %q", name)
}
// WriteFile always succeeds and does nothing.
func (fs *fsInMemory) WriteFile(name string, c []byte) error {
ff := &fileInMemory{}
ff.Write(c)
fs.m[name] = ff
return nil
}
// Walk implements filepath.Walk using the fake filesystem.
func (fs *fsInMemory) Walk(path string, walkFn filepath.WalkFunc) error {
info, err := fs.lstat(path)
if err != nil {
err = walkFn(path, info, err)
} else {
err = fs.walk(path, info, walkFn)
}
if err == filepath.SkipDir {
return nil
}
return err
}
func (fs *fsInMemory) pathMatch(path, pattern string) bool {
match, _ := filepath.Match(pattern, path)
return match
}
func (fs *fsInMemory) lstat(path string) (*fileInfo, error) {
f, found := fs.m[path]
if !found {
return nil, os.ErrNotExist
}
return &fileInfo{f}, nil
}
func (fs *fsInMemory) join(elem ...string) string {
for i, e := range elem {
if e != "" {
return strings.Replace(
strings.Join(elem[i:], separator), doubleSep, separator, -1)
}
}
return ""
}
func (fs *fsInMemory) readDirNames(path string) []string {
var names []string
if !strings.HasSuffix(path, separator) {
path += separator
}
pathSegments := strings.Count(path, separator)
for name := range fs.m {
if name == path {
continue
}
if strings.Count(name, separator) > pathSegments {
continue
}
if strings.HasPrefix(name, path) {
names = append(names, filepath.Base(name))
}
}
sort.Strings(names)
return names
}
func (fs *fsInMemory) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if !info.IsDir() {
return walkFn(path, info, nil)
}
names := fs.readDirNames(path)
if err := walkFn(path, info, nil); err != nil {
return err
}
for _, name := range names {
filename := fs.join(path, name)
fileInfo, err := fs.lstat(filename)
if err != nil {
if err := walkFn(filename, fileInfo, os.ErrNotExist); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = fs.walk(filename, fileInfo, walkFn)
if err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}

View File

@@ -1,149 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys_test
import (
"bytes"
"reflect"
"testing"
. "sigs.k8s.io/kustomize/api/filesys"
)
func TestExists(t *testing.T) {
fSys := MakeFsInMemory()
if fSys.Exists("foo") {
t.Fatalf("expected no foo")
}
fSys.Mkdir("/")
if !fSys.IsDir("/") {
t.Fatalf("expected dir at /")
}
}
func TestIsDir(t *testing.T) {
fSys := MakeFsInMemory()
expectedName := "my-dir"
err := fSys.Mkdir(expectedName)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
shouldExist(t, fSys, expectedName)
if !fSys.IsDir(expectedName) {
t.Fatalf(expectedName + " should be a dir")
}
}
func shouldExist(t *testing.T, fSys FileSystem, name string) {
if !fSys.Exists(name) {
t.Fatalf(name + " should exist")
}
}
func shouldNotExist(t *testing.T, fSys FileSystem, name string) {
if fSys.Exists(name) {
t.Fatalf(name + " should not exist")
}
}
func TestRemoveAll(t *testing.T) {
fSys := MakeFsInMemory()
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/apple/subdir/file.yaml", []byte("Unused"))
shouldExist(t, fSys, "/foo/project/file.yaml")
shouldExist(t, fSys, "/foo/project/subdir/file.yaml")
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
err := fSys.RemoveAll("/foo/project")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
shouldNotExist(t, fSys, "/foo/project/file.yaml")
shouldNotExist(t, fSys, "/foo/project/subdir/file.yaml")
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
}
func TestIsDirDeeper(t *testing.T) {
fSys := MakeFsInMemory()
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
if !fSys.IsDir("/") {
t.Fatalf("/ should be a dir")
}
if !fSys.IsDir("/foo") {
t.Fatalf("/foo should be a dir")
}
if !fSys.IsDir("/foo/project") {
t.Fatalf("/foo/project should be a dir")
}
if fSys.IsDir("/fo") {
t.Fatalf("/fo should not be a dir")
}
if fSys.IsDir("/x") {
t.Fatalf("/x should not be a dir")
}
}
func TestCreate(t *testing.T) {
fSys := MakeFsInMemory()
f, err := fSys.Create("foo")
if f == nil {
t.Fatalf("expected file")
}
if err != nil {
t.Fatalf("unexpected error")
}
shouldExist(t, fSys, "foo")
}
func TestReadFile(t *testing.T) {
fSys := MakeFsInMemory()
f, err := fSys.Create("foo")
if f == nil {
t.Fatalf("expected file")
}
if err != nil {
t.Fatalf("unexpected error")
}
content, err := fSys.ReadFile("foo")
if len(content) != 0 {
t.Fatalf("expected no content")
}
if err != nil {
t.Fatalf("expected no error")
}
}
func TestWriteFile(t *testing.T) {
fSys := MakeFsInMemory()
c := []byte("heybuddy")
err := fSys.WriteFile("foo", c)
if err != nil {
t.Fatalf("expected no error")
}
content, err := fSys.ReadFile("foo")
if err != nil {
t.Fatalf("expected read to work: %v", err)
}
if bytes.Compare(c, content) != 0 {
t.Fatalf("incorrect content: %v", content)
}
}
func TestGlob(t *testing.T) {
fSys := MakeFsInMemory()
fSys.Create("dir/foo")
fSys.Create("dir/bar")
files, err := fSys.Glob("dir/*")
if err != nil {
t.Fatalf("expected no error")
}
expected := []string{
"dir/bar",
"dir/foo",
}
if !reflect.DeepEqual(files, expected) {
t.Fatalf("incorrect files found by glob: %v", files)
}
}

View File

@@ -1,12 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import "path/filepath"
// RootedPath returns a rooted path, e.g. "/foo/bar" as
// opposed to "foo/bar".
func RootedPath(elem ...string) string {
return separator + filepath.Join(elem...)
}

View File

@@ -1,21 +0,0 @@
module sigs.k8s.io/kustomize/api
go 1.13
require (
github.com/evanphx/json-patch v4.5.0+incompatible
github.com/go-openapi/spec v0.19.4
github.com/golang/protobuf v1.3.2 // indirect
github.com/pkg/errors v0.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0 // indirect
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 // indirect
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.4
k8s.io/api v0.0.0-20191016225839-816a9b7df678
k8s.io/apimachinery v0.0.0-20191020214737-6c8691705fc5
k8s.io/client-go v11.0.0+incompatible
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d
sigs.k8s.io/yaml v1.1.0
)

View File

@@ -1,162 +0,0 @@
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/api v0.0.0-20191016225839-816a9b7df678 h1:z/0BV/tMBIvdwZvqBH/f7TWjQX9y3dj1nMNhrSK0h/8=
k8s.io/api v0.0.0-20191016225839-816a9b7df678/go.mod h1:LZQaT8MvVpl7Bg2lYFcQm7+Mpdxq8p1NFl3yh+5DCwY=
k8s.io/apimachinery v0.0.0-20191016225534-b1267f8c42b4/go.mod h1:92mWDd8Ji2sw2157KIgino5wCxffA8KSvhW2oY4ypdw=
k8s.io/apimachinery v0.0.0-20191020214737-6c8691705fc5 h1:r3/YL3+t1U46lJF5zUSArskUpnLyWuM28rQDpM1qQPI=
k8s.io/apimachinery v0.0.0-20191020214737-6c8691705fc5/go.mod h1:92mWDd8Ji2sw2157KIgino5wCxffA8KSvhW2oY4ypdw=
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY=
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -1,274 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"fmt"
"log"
"sigs.k8s.io/kustomize/api/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/transform"
)
type nameReferenceTransformer struct {
backRefs []builtinconfig.NameBackReferences
}
var _ resmap.Transformer = &nameReferenceTransformer{}
// newNameReferenceTransformer constructs a nameReferenceTransformer
// with a given slice of NameBackReferences.
func newNameReferenceTransformer(br []builtinconfig.NameBackReferences) resmap.Transformer {
if br == nil {
log.Fatal("backrefs not expected to be nil")
}
return &nameReferenceTransformer{backRefs: br}
}
// Transform updates name references in resource A that
// refer to resource B, given that B's name may have
// changed.
//
// For example, a HorizontalPodAutoscaler (HPA)
// necessarily refers to a Deployment, the thing that
// the HPA scales. The Deployment name might change
// (e.g. prefix added), and the reference in the HPA
// has to be fixed.
//
// In the outer loop over the ResMap below, say we
// encounter a specific HPA. Then, in scanning backrefs,
// we encounter an entry like
//
// - kind: Deployment
// fieldSpecs:
// - kind: HorizontalPodAutoscaler
// path: spec/scaleTargetRef/name
//
// This entry says that an HPA, via its
// 'spec/scaleTargetRef/name' field, may refer to a
// Deployment. This match to HPA means we may need to
// modify the value in its 'spec/scaleTargetRef/name'
// field, by searching for the thing it refers to,
// and getting its new name.
//
// As a filter, and search optimization, we compute a
// subset of all resources that the HPA could refer to,
// by excluding objects from other namespaces, and
// excluding objects that don't have the same prefix-
// suffix mods as the HPA.
//
// We look in this subset for all Deployment objects
// with a resId that has a Name matching the field value
// present in the HPA. If no match do nothing; if more
// than one match, it's an error.
//
// We overwrite the HPA name field with the value found
// in the Deployment's name field (the name in the raw
// object - the modified name - not the unmodified name
// in the Deployment's resId).
//
// This process assumes that the name stored in a ResId
// (the ResMap key) isn't modified by name transformers.
// Name transformers should only modify the name in the
// body of the resource object (the value in the ResMap).
//
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
// TODO: Too much looping, here and in transitive calls.
for _, referrer := range m.Resources() {
var candidates resmap.ResMap
for _, target := range o.backRefs {
for _, fSpec := range target.FieldSpecs {
if referrer.OrgId().IsSelected(&fSpec.Gvk) {
if candidates == nil {
candidates = m.SubsetThatCouldBeReferencedByResource(referrer)
}
err := transform.MutateField(
referrer.Map(),
fSpec.PathSlice(),
fSpec.CreateIfNotPresent,
o.getNewNameFunc(
// referrer could be an HPA instance,
// target could be Gvk for Deployment,
// candidate a list of resources "reachable"
// from the HPA.
referrer, target.Gvk, candidates))
if err != nil {
return err
}
}
}
}
}
return nil
}
// selectReferral picks the referral among a subset of candidates.
// It returns the current name and namespace of the selected candidate.
// Note that the content of the referricalCandidateSubset slice is most of the time
// identical to the referralCandidates resmap. Still in some cases, such
// as ClusterRoleBinding, the subset only contains the resources of a specific
// namespace.
func (o *nameReferenceTransformer) selectReferral(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (interface{}, interface{}, error) {
for _, res := range referralCandidateSubset {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match, there's no way
// to know which one to pick, so emit error.
if len(matches) > 1 {
return nil, nil, fmt.Errorf(
"multiple matches for %s:\n %v",
id, getIds(matches))
}
// In the resource, note that it is referenced
// by the referrer.
res.AppendRefBy(referrer.CurId())
// Return transformed name of the object,
// complete with prefixes, hashes, etc.
return res.GetName(), res.GetNamespace(), nil
}
}
return oldName, nil, nil
}
// utility function to replace a simple string by the new name
func (o *nameReferenceTransformer) getSimpleNameField(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (interface{}, error) {
newName, _, err := o.selectReferral(oldName, referrer, target,
referralCandidates, referralCandidateSubset)
return newName, err
}
// utility function to replace name field within a map[string]interface{}
// and leverage the namespace field.
func (o *nameReferenceTransformer) getNameAndNsStruct(
inMap map[string]interface{},
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap) (interface{}, error) {
// Example:
if _, ok := inMap["name"]; !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field", inMap)
}
oldName, ok := inMap["name"].(string)
if !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field of type string", oldName)
}
subset := referralCandidates.Resources()
if namespacevalue, ok := inMap["namespace"]; ok {
namespace := namespacevalue.(string)
bynamespace := referralCandidates.GroupedByOriginalNamespace()
if _, ok := bynamespace[namespace]; !ok {
return inMap, nil
}
subset = bynamespace[namespace]
}
newname, newnamespace, err := o.selectReferral(oldName, referrer, target,
referralCandidates, subset)
if err != nil {
return nil, err
}
if (newname == oldName) && (newnamespace == nil) {
// no candidate found.
return inMap, nil
}
inMap["name"] = newname
if newnamespace != "" {
// We don't want value "" to replace value "default" since
// the empty string is handled as a wild card here not default namespace
// by kubernetes.
inMap["namespace"] = newnamespace
}
return inMap, nil
}
func (o *nameReferenceTransformer) getNewNameFunc(
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) {
switch in.(type) {
case string:
oldName, _ := in.(string)
return o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
case map[string]interface{}:
// Kind: ValidatingWebhookConfiguration
// FieldSpec is webhooks/clientConfig/service
oldMap, _ := in.(map[string]interface{})
return o.getNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
case []interface{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case string:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
oldName, _ := item.(string)
newName, err := o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
if err != nil {
return nil, err
}
l[idx] = newName
case map[string]interface{}:
// Kind: RoleBinding/ClusterRoleBinding
// FieldSpec is subjects
// Note: The corresponding fieldSpec had been changed from
// from path: subjects/name to just path: subjects. This is
// what get mutatefield to request the mapping of the whole
// map containing namespace and name instead of just a simple
// string field containing the name
oldMap, _ := item.(map[string]interface{})
newMap, err := o.getNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
if err != nil {
return nil, err
}
l[idx] = newMap
default:
return nil, fmt.Errorf(
"%#v is expected to be either a []string or a []map[string]interface{}", in)
}
}
return in, nil
default:
return nil, fmt.Errorf(
"%#v is expected to be either a string or a []interface{}", in)
}
}
}
func getIds(rs []*resource.Resource) []string {
var result []string
for _, r := range rs {
result = append(result, r.CurId().String()+"\n")
}
return result
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,137 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/testutils/resmaptest"
"sigs.k8s.io/kustomize/api/types"
)
func TestRefVarTransformer(t *testing.T) {
type given struct {
varMap map[string]interface{}
fs []types.FieldSpec
res resmap.ResMap
}
type expected struct {
res resmap.ResMap
unused []string
}
testCases := []struct {
description string
given given
expected expected
}{
{
description: "var replacement in map[string]",
given: given{
varMap: map[string]interface{}{
"FOO": "replacementForFoo",
"BAR": "replacementForBar",
"BAZ": int64(5),
"BOO": true,
},
fs: []types.FieldSpec{
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/map"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"},
},
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"map": map[string]interface{}{
"item1": "$(FOO)",
"item2": "bla",
"item3": "$(BAZ)",
"item4": "$(BAZ)+$(BAZ)",
"item5": "$(BOO)",
"item6": "if $(BOO)",
"item7": 2019,
},
"slice": []interface{}{
"$(FOO)",
"bla",
"$(BAZ)",
"$(BAZ)+$(BAZ)",
"$(BOO)",
"if $(BOO)",
},
"interface": "$(FOO)",
"nil": nil,
"num": 2019,
}}).ResMap(),
},
expected: expected{
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"map": map[string]interface{}{
"item1": "replacementForFoo",
"item2": "bla",
"item3": int64(5),
"item4": "5+5",
"item5": true,
"item6": "if true",
"item7": 2019,
},
"slice": []interface{}{
"replacementForFoo",
"bla",
int64(5),
"5+5",
true,
"if true",
},
"interface": "replacementForFoo",
"nil": nil,
"num": 2019,
}}).ResMap(),
unused: []string{"BAR"},
},
},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
// arrange
tr := newRefVarTransformer(tc.given.varMap, tc.given.fs)
// act
err := tr.Transform(tc.given.res)
// assert
if err != nil {
t.Errorf("unexpected error: %v", err)
}
a, e := tc.given.res, tc.expected.res
if !reflect.DeepEqual(a, e) {
err = e.ErrorIfNotEqualLists(a)
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
}
})
}
}

View File

@@ -1,34 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package loader has a data loading interface and various implementations.
package loader
import (
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/git"
"sigs.k8s.io/kustomize/api/ifc"
)
// NewLoader returns a Loader pointed at the given target.
// If the target is remote, the loader will be restricted
// to the root and below only. If the target is local, the
// loader will have the restrictions passed in. Regardless,
// if a local target attempts to transitively load remote bases,
// the remote bases will all be root-only restricted.
func NewLoader(
lr LoadRestrictorFunc,
target string, fSys filesys.FileSystem) (ifc.Loader, error) {
repoSpec, err := git.NewRepoSpecFromUrl(target)
if err == nil {
// The target qualifies as a remote git target.
return newLoaderAtGitClone(
repoSpec, fSys, nil, git.ClonerUsingGitExec)
}
root, err := demandDirectoryRoot(fSys, target)
if err != nil {
return nil, err
}
return newLoaderAtConfirmedDir(
lr, root, fSys, nil, git.ClonerUsingGitExec), nil
}

View File

@@ -1,21 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// A dummy main to help with releasing the kustomize API module.
package main
import (
"fmt"
"os"
"sigs.k8s.io/kustomize/api/provenance"
)
// TODO: delete this when we find a better way to generate release notes.
func main() {
fmt.Println(`
This 'main' exists only to make goreleaser create release notes for the API.
See https://github.com/goreleaser/goreleaser/issues/981
and https://github.com/kubernetes-sigs/kustomize/tree/master/releasing`)
provenance.GetProvenance().Print(os.Stdout, false)
}

View File

@@ -1,41 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package pgmconfig
// RecognizedKustomizationFileNames is a list of file names
// that kustomize recognizes.
// To avoid ambiguity, a kustomization directory may not
// contain more than one match to this list.
func RecognizedKustomizationFileNames() []string {
return []string{
"kustomization.yaml",
"kustomization.yml",
"Kustomization",
}
}
func DefaultKustomizationFileName() string {
return RecognizedKustomizationFileNames()[0]
}
const (
// An environment variable to consult for kustomization
// configuration data. See:
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
XdgConfigHome = "XDG_CONFIG_HOME"
// Use this when XdgConfigHome not defined.
DefaultConfigSubdir = ".config"
// Program name, for help, finding the XDG_CONFIG_DIR, etc.
ProgramName = "kustomize"
// TODO: delete this. it's a copy of a const
// defined elsewhere but used by pluginator.
DomainName = "sigs.k8s.io"
// TODO: delete this. its a copy of a const
// defined elsewhere but used by pluginator.
PluginRoot = "plugin"
)

View File

@@ -1,5 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package consts provides builtin plugin configuration data.
package consts

View File

@@ -1,10 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package consts
const (
// imageFieldSpecs is left empty since `containers` and `initContainers`
// of *ANY* kind in *ANY* path are builtin supported in code
imagesFieldSpecs = ``
)

View File

@@ -1,11 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package consts
const (
namePrefixFieldSpecs = `
namePrefix:
- path: metadata/name
`
)

View File

@@ -1,16 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package consts
const (
namespaceFieldSpecs = `
namespace:
- path: metadata/namespace
create: true
- path: subjects
kind: RoleBinding
- path: subjects
kind: ClusterRoleBinding
`
)

View File

@@ -1,10 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package builtinconfig provides legacy methods for
// configuring builtin plugins from a common config file.
// As a user, its best to configure plugins individually
// with plugin config files specified in the `transformers:`
// or `generators:` field, than to use this legacy
// configuration technique.
package builtinconfig

View File

@@ -1,42 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/yaml"
)
// loadDefaultConfig returns a TranformerConfig
// object from a list of files.
func loadDefaultConfig(
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
result := &TransformerConfig{}
for _, path := range paths {
data, err := ldr.Load(path)
if err != nil {
return nil, err
}
t, err := makeTransformerConfigFromBytes(data)
if err != nil {
return nil, err
}
result, err = result.Merge(t)
if err != nil {
return nil, err
}
}
return result, nil
}
// makeTransformerConfigFromBytes returns a TransformerConfig object from bytes
func makeTransformerConfigFromBytes(data []byte) (*TransformerConfig, error) {
var t TransformerConfig
err := yaml.Unmarshal(data, &t)
if err != nil {
return nil, err
}
t.sortFields()
return &t, nil
}

View File

@@ -1,148 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"log"
"sort"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/plugins/builtinconfig/consts"
"sigs.k8s.io/kustomize/api/types"
)
// TransformerConfig holds the data needed to perform transformations.
type TransformerConfig struct {
NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"`
Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"`
}
// MakeEmptyConfig returns an empty TransformerConfig object
func MakeEmptyConfig() *TransformerConfig {
return &TransformerConfig{}
}
// MakeDefaultConfig returns a default TransformerConfig.
func MakeDefaultConfig() *TransformerConfig {
c, err := makeTransformerConfigFromBytes(
consts.GetDefaultFieldSpecs())
if err != nil {
log.Fatalf("Unable to make default transformconfig: %v", err)
}
return c
}
// MakeTransformerConfig returns a merger of custom config,
// if any, with default config.
func MakeTransformerConfig(
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
t1 := MakeDefaultConfig()
if len(paths) == 0 {
return t1, nil
}
t2, err := loadDefaultConfig(ldr, paths)
if err != nil {
return nil, err
}
return t1.Merge(t2)
}
// sortFields provides determinism in logging, tests, etc.
func (t *TransformerConfig) sortFields() {
sort.Sort(t.NamePrefix)
sort.Sort(t.NameSpace)
sort.Sort(t.CommonLabels)
sort.Sort(t.CommonAnnotations)
sort.Sort(t.NameReference)
sort.Sort(t.VarReference)
sort.Sort(t.Images)
sort.Sort(t.Replicas)
}
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix
func (t *TransformerConfig) AddPrefixFieldSpec(fs types.FieldSpec) (err error) {
t.NamePrefix, err = t.NamePrefix.MergeOne(fs)
return err
}
// AddSuffixFieldSpec adds a FieldSpec to NameSuffix
func (t *TransformerConfig) AddSuffixFieldSpec(fs types.FieldSpec) (err error) {
t.NameSuffix, err = t.NameSuffix.MergeOne(fs)
return err
}
// AddLabelFieldSpec adds a FieldSpec to CommonLabels
func (t *TransformerConfig) AddLabelFieldSpec(fs types.FieldSpec) (err error) {
t.CommonLabels, err = t.CommonLabels.MergeOne(fs)
return err
}
// AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations
func (t *TransformerConfig) AddAnnotationFieldSpec(fs types.FieldSpec) (err error) {
t.CommonAnnotations, err = t.CommonAnnotations.MergeOne(fs)
return err
}
// AddNamereferenceFieldSpec adds a NameBackReferences to NameReference
func (t *TransformerConfig) AddNamereferenceFieldSpec(
nbrs NameBackReferences) (err error) {
t.NameReference, err = t.NameReference.mergeOne(nbrs)
return err
}
// Merge merges two TransformerConfigs objects into
// a new TransformerConfig object
func (t *TransformerConfig) Merge(input *TransformerConfig) (
merged *TransformerConfig, err error) {
if input == nil {
return t, nil
}
merged = &TransformerConfig{}
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
if err != nil {
return nil, err
}
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
if err != nil {
return nil, err
}
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
if err != nil {
return nil, err
}
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
input.CommonAnnotations)
if err != nil {
return nil, err
}
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
if err != nil {
return nil, err
}
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
if err != nil {
return nil, err
}
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
if err != nil {
return nil, err
}
merged.Images, err = t.Images.MergeAll(input.Images)
if err != nil {
return nil, err
}
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
if err != nil {
return nil, err
}
merged.sortFields()
return merged, nil
}

View File

@@ -1,37 +0,0 @@
// Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT.
package builtinhelpers
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Unknown-0]
_ = x[AnnotationsTransformer-1]
_ = x[ConfigMapGenerator-2]
_ = x[HashTransformer-3]
_ = x[ImageTagTransformer-4]
_ = x[InventoryTransformer-5]
_ = x[LabelTransformer-6]
_ = x[LegacyOrderTransformer-7]
_ = x[NamespaceTransformer-8]
_ = x[PatchJson6902Transformer-9]
_ = x[PatchStrategicMergeTransformer-10]
_ = x[PatchTransformer-11]
_ = x[PrefixSuffixTransformer-12]
_ = x[ReplicaCountTransformer-13]
_ = x[SecretGenerator-14]
}
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerInventoryTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGenerator"
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 101, 117, 139, 159, 183, 213, 229, 252, 275, 290}
func (i BuiltinPluginType) String() string {
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
return "BuiltinPluginType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _BuiltinPluginType_name[_BuiltinPluginType_index[i]:_BuiltinPluginType_index[i+1]]
}

View File

@@ -1,75 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinhelpers
import (
"sigs.k8s.io/kustomize/api/plugins/builtins"
"sigs.k8s.io/kustomize/api/resmap"
)
//go:generate stringer -type=BuiltinPluginType
type BuiltinPluginType int
const (
Unknown BuiltinPluginType = iota
AnnotationsTransformer
ConfigMapGenerator
HashTransformer
ImageTagTransformer
InventoryTransformer
LabelTransformer
LegacyOrderTransformer
NamespaceTransformer
PatchJson6902Transformer
PatchStrategicMergeTransformer
PatchTransformer
PrefixSuffixTransformer
ReplicaCountTransformer
SecretGenerator
)
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
func init() {
stringToBuiltinPluginTypeMap = makeStringToBuiltinPluginTypeMap()
}
func makeStringToBuiltinPluginTypeMap() (result map[string]BuiltinPluginType) {
result = make(map[string]BuiltinPluginType, 23)
for k := range GeneratorFactories {
result[k.String()] = k
}
for k := range TransformerFactories {
result[k.String()] = k
}
return
}
func GetBuiltinPluginType(n string) BuiltinPluginType {
result, ok := stringToBuiltinPluginTypeMap[n]
if ok {
return result
}
return Unknown
}
var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
SecretGenerator: builtins.NewSecretGeneratorPlugin,
}
var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{
AnnotationsTransformer: builtins.NewAnnotationsTransformerPlugin,
HashTransformer: builtins.NewHashTransformerPlugin,
ImageTagTransformer: builtins.NewImageTagTransformerPlugin,
InventoryTransformer: builtins.NewInventoryTransformerPlugin,
LabelTransformer: builtins.NewLabelTransformerPlugin,
LegacyOrderTransformer: builtins.NewLegacyOrderTransformerPlugin,
NamespaceTransformer: builtins.NewNamespaceTransformerPlugin,
PatchJson6902Transformer: builtins.NewPatchJson6902TransformerPlugin,
PatchStrategicMergeTransformer: builtins.NewPatchStrategicMergeTransformerPlugin,
PatchTransformer: builtins.NewPatchTransformerPlugin,
PrefixSuffixTransformer: builtins.NewPrefixSuffixTransformerPlugin,
ReplicaCountTransformer: builtins.NewReplicaCountTransformerPlugin,
}

View File

@@ -1,42 +0,0 @@
// Code generated by pluginator on AnnotationsTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Add the given annotations to the given field specifications.
type AnnotationsTransformerPlugin struct {
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *AnnotationsTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Annotations = nil
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
t, err := transform.NewMapTransformer(
p.FieldSpecs,
p.Annotations,
)
if err != nil {
return err
}
return t.Transform(m)
}
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
return &AnnotationsTransformerPlugin{}
}

View File

@@ -1,42 +0,0 @@
// Code generated by pluginator on LabelTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Add the given labels to the given field specifications.
type LabelTransformerPlugin struct {
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *LabelTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Labels = nil
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
t, err := transform.NewMapTransformer(
p.FieldSpecs,
p.Labels,
)
if err != nil {
return err
}
return t.Transform(m)
}
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
return &LabelTransformerPlugin{}
}

View File

@@ -1,134 +0,0 @@
// Code generated by pluginator on NamespaceTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Change or set the namespace of non-cluster level resources.
type NamespaceTransformerPlugin struct {
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *NamespaceTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Namespace = ""
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
if len(p.Namespace) == 0 {
return nil
}
for _, r := range m.Resources() {
if len(r.Map()) == 0 {
// Don't mutate empty objects?
continue
}
id := r.OrgId()
applicableFs := p.applicableFieldSpecs(id)
for _, fs := range applicableFs {
err := transform.MutateField(
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
p.changeNamespace(r))
if err != nil {
return err
}
}
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
if len(matches) != 1 {
return fmt.Errorf("namespace tranformation produces ID conflict: %#v", matches)
}
}
return nil
}
const metaNamespace = "metadata/namespace"
// Special casing metadata.namespace since
// all objects have it, even "ClusterKind" objects
// that don't exist in a namespace (the Namespace
// object itself doesn't live in a namespace).
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []types.FieldSpec {
var res []types.FieldSpec
for _, fs := range p.FieldSpecs {
if id.IsSelected(&fs.Gvk) && (fs.Path != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
res = append(res, fs)
}
}
return res
}
func (p *NamespaceTransformerPlugin) changeNamespace(
referrer *resource.Resource) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) {
switch in.(type) {
case string:
// will happen when the metadata/namespace
// value is replaced
return p.Namespace, nil
case []interface{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case map[string]interface{}:
// Will happen when mutating the subjects
// field of ClusterRoleBinding and RoleBinding
inMap, _ := item.(map[string]interface{})
if _, ok := inMap["name"]; !ok {
continue
}
name, ok := inMap["name"].(string)
if !ok {
continue
}
// The only case we need to force the namespace
// if for the "service account". "default" is
// kind of hardcoded here for right now.
if name != "default" {
continue
}
inMap["namespace"] = p.Namespace
l[idx] = inMap
default:
// nothing to do for right now
}
}
return in, nil
case map[string]interface{}:
// Will happen if the createField=true
// when the namespace is added to the
// object
inMap := in.(map[string]interface{})
if len(inMap) == 0 {
return p.Namespace, nil
} else {
return in, nil
}
default:
return in, nil
}
}
}
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
return &NamespaceTransformerPlugin{}
}

View File

@@ -1,93 +0,0 @@
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type PatchStrategicMergeTransformerPlugin struct {
h *resmap.PluginHelpers
loadedPatches []*resource.Resource
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
}
func (p *PatchStrategicMergeTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.h = h
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if len(p.Paths) == 0 && p.Patches == "" {
return fmt.Errorf("empty file path and empty patch content")
}
if len(p.Paths) != 0 {
for _, onePath := range p.Paths {
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
if err == nil {
p.loadedPatches = append(p.loadedPatches, res...)
continue
}
res, err = p.h.ResmapFactory().RF().SliceFromPatches(
p.h.Loader(), []types.PatchStrategicMerge{onePath})
if err != nil {
return err
}
p.loadedPatches = append(p.loadedPatches, res...)
}
}
if p.Patches != "" {
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
if err != nil {
return err
}
p.loadedPatches = append(p.loadedPatches, res...)
}
if len(p.loadedPatches) == 0 {
return fmt.Errorf(
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
}
return err
}
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
if err != nil {
return err
}
for _, patch := range patches.Resources() {
target, err := m.GetById(patch.OrgId())
if err != nil {
return err
}
err = target.Patch(patch.Kunstructured)
if err != nil {
return err
}
// remove the resource from resmap
// when the patch is to $patch: delete that target
if len(target.Map()) == 0 {
err = m.Remove(target.CurId())
if err != nil {
return err
}
}
}
return nil
}
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
return &PatchStrategicMergeTransformerPlugin{}
}

View File

@@ -1,148 +0,0 @@
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"fmt"
"github.com/evanphx/json-patch"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type PatchTransformerPlugin struct {
loadedPatch *resource.Resource
decodedPatch jsonpatch.Patch
Path string `json:"path,omitempty" yaml:"path,omitempty"`
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
}
func (p *PatchTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if p.Patch == "" && p.Path == "" {
err = fmt.Errorf(
"must specify one of patch and path in\n%s", string(c))
return
}
if p.Patch != "" && p.Path != "" {
err = fmt.Errorf(
"patch and path can't be set at the same time\n%s", string(c))
return
}
var in []byte
if p.Path != "" {
in, err = h.Loader().Load(p.Path)
if err != nil {
return
}
}
if p.Patch != "" {
in = []byte(p.Patch)
}
patchSM, errSM := h.ResmapFactory().RF().FromBytes(in)
patchJson, errJson := jsonPatchFromBytes(in)
if errSM != nil && errJson != nil {
err = fmt.Errorf(
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
return
}
if errSM == nil && errJson != nil {
p.loadedPatch = patchSM
}
if errJson == nil && errSM != nil {
p.decodedPatch = patchJson
}
if patchSM != nil && patchJson != nil {
err = fmt.Errorf(
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
}
return nil
}
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
if p.loadedPatch != nil && p.Target == nil {
target, err := m.GetById(p.loadedPatch.OrgId())
if err != nil {
return err
}
err = target.Patch(p.loadedPatch.Kunstructured)
if err != nil {
return err
}
return nil
}
if p.Target == nil {
return fmt.Errorf("must specify a target for patch %s", p.Patch)
}
resources, err := m.Select(*p.Target)
if err != nil {
return err
}
for _, res := range resources {
if p.decodedPatch != nil {
rawObj, err := res.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := p.decodedPatch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.Patch)
}
err = res.UnmarshalJSON(modifiedObj)
if err != nil {
return err
}
}
if p.loadedPatch != nil {
patchCopy := p.loadedPatch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk())
err = res.Patch(patchCopy.Kunstructured)
if err != nil {
return err
}
}
}
return nil
}
// jsonPatchFromBytes loads a Json 6902 patch from
// a bytes input
func jsonPatchFromBytes(
in []byte) (jsonpatch.Patch, error) {
ops := string(in)
if ops == "" {
return nil, fmt.Errorf("empty json patch operations")
}
if ops[0] != '[' {
jsonOps, err := yaml.YAMLToJSON(in)
if err != nil {
return nil, err
}
ops = string(jsonOps)
}
return jsonpatch.DecodePatch([]byte(ops))
}
func NewPatchTransformerPlugin() resmap.TransformerPlugin {
return &PatchTransformerPlugin{}
}

View File

@@ -1,126 +0,0 @@
// Code generated by pluginator on PrefixSuffixTransformer; DO NOT EDIT.
// pluginator {Version:unknown GitCommit:$Format:%H$ BuildDate:1970-01-01T00:00:00Z GoOs:linux GoArch:amd64}
package builtins
import (
"errors"
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/yaml"
)
// Add the given prefix and suffix to the field.
type PrefixSuffixTransformerPlugin struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
// Not placed in a file yet due to lack of demand.
var prefixSuffixFieldSpecsToSkip = []types.FieldSpec{
{
Gvk: resid.Gvk{Kind: "CustomResourceDefinition"},
},
{
Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"},
},
}
func (p *PrefixSuffixTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Prefix = ""
p.Suffix = ""
p.FieldSpecs = nil
err = yaml.Unmarshal(c, p)
if err != nil {
return
}
if p.FieldSpecs == nil {
return errors.New("fieldSpecs is not expected to be nil")
}
return
}
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
// Even if both the Prefix and Suffix are empty we want
// to proceed with the transformation. This allows to add contextual
// information to the resources (AddNamePrefix and AddNameSuffix).
for _, r := range m.Resources() {
if p.shouldSkip(r.OrgId()) {
// Don't change the actual definition
// of a CRD.
continue
}
id := r.OrgId()
// current default configuration contains
// only one entry: "metadata/name" with no GVK
for _, path := range p.FieldSpecs {
if !id.IsSelected(&path.Gvk) {
// With the currrent default configuration,
// because no Gvk is specified, so a wild
// card
continue
}
if smellsLikeANameChange(&path) {
// "metadata/name" is the only field.
// this will add a prefix and a suffix
// to the resource even if those are
// empty
r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix)
}
// the addPrefixSuffix method will not
// change the name if both the prefix and suffix
// are empty.
err := transform.MutateField(
r.Map(),
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
if err != nil {
return err
}
}
}
return nil
}
func smellsLikeANameChange(fs *types.FieldSpec) bool {
return fs.Path == "metadata/name"
}
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) {
return true
}
}
return false
}
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)
if !ok {
return nil, fmt.Errorf("%#v is expected to be %T", in, s)
}
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
}
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
return &PrefixSuffixTransformerPlugin{}
}

View File

@@ -1,8 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package builtins holds code generated from the builtin plugins.
// The "builtin" plugins are written as normal plugins and can
// be used as such, but they are also used to generate the code
// in this package so they can be statically linked to client code.
package builtins

View File

@@ -1,17 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// +build tools
// This file exists to declare that its containing
// package explicitly depends on the pluginator
// tool (via go:generate directives)
package builtins
// TODO: replace this, with the appropriate version
// once the API is launched, and the new pluginator
// has been compiled against it and released.
//
// import (
// _ "sigs.k8s.io/kustomize/pluginator"
// )

View File

@@ -1,97 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package config provides configuration methods and constants
// for general plugins.
package config
import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/spf13/pflag"
"sigs.k8s.io/kustomize/api/pgmconfig"
"sigs.k8s.io/kustomize/api/types"
)
const (
// Used with Go plugins.
PluginSymbol = "KustomizePlugin"
// Location of builtins.
BuiltinPluginPackage = "builtin"
// ApiVersion of builtins.
BuiltinPluginApiVersion = BuiltinPluginPackage
// Domain from which kustomize code is imported, for locating
// plugin source code under $GOPATH.
DomainName = "sigs.k8s.io"
// Name of directory housing all plugins.
PluginRoot = "plugin"
flagEnablePluginsName = "enable_alpha_plugins"
flagEnablePluginsHelp = `enable plugins, an alpha feature.
See https://github.com/kubernetes-sigs/kustomize/blob/master/docs/plugins/README.md
`
flagErrorFmt = `
unable to load external plugin %s because plugins disabled
specify the flag
--%s
to %s`
)
func ActivePluginConfig() *types.PluginConfig {
pc := DefaultPluginConfig()
pc.Enabled = true
return pc
}
func DefaultPluginConfig() *types.PluginConfig {
return &types.PluginConfig{
Enabled: false,
DirectoryPath: filepath.Join(configRoot(), PluginRoot),
}
}
func NotEnabledErr(name string) error {
return fmt.Errorf(
flagErrorFmt,
name,
flagEnablePluginsName,
flagEnablePluginsHelp)
}
func AddFlagEnablePlugins(set *pflag.FlagSet, v *bool) {
set.BoolVar(
v, flagEnablePluginsName,
false, flagEnablePluginsHelp)
}
// Use https://github.com/kirsle/configdir instead?
func configRoot() string {
dir := os.Getenv(pgmconfig.XdgConfigHome)
if len(dir) == 0 {
dir = filepath.Join(
HomeDir(), pgmconfig.DefaultConfigSubdir)
}
return filepath.Join(dir, pgmconfig.ProgramName)
}
func HomeDir() string {
home := os.Getenv(homeEnv())
if len(home) > 0 {
return home
}
return "~"
}
func homeEnv() string {
if runtime.GOOS == "windows" {
return "USERPROFILE"
}
return "HOME"
}

View File

@@ -1,45 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package config
import (
"os"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/pgmconfig"
)
func TestConfigDirNoXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(pgmconfig.XdgConfigHome)
if isSet {
os.Unsetenv(pgmconfig.XdgConfigHome)
}
s := configRoot()
if isSet {
os.Setenv(pgmconfig.XdgConfigHome, xdg)
}
if !strings.HasSuffix(
s,
rootedPath(pgmconfig.DefaultConfigSubdir, pgmconfig.ProgramName)) {
t.Fatalf("unexpected config dir: %s", s)
}
}
func rootedPath(elem ...string) string {
return string(filepath.Separator) + filepath.Join(elem...)
}
func TestConfigDirWithXdg(t *testing.T) {
xdg, isSet := os.LookupEnv(pgmconfig.XdgConfigHome)
os.Setenv(pgmconfig.XdgConfigHome, rootedPath("blah"))
s := configRoot()
if isSet {
os.Setenv(pgmconfig.XdgConfigHome, xdg)
}
if s != rootedPath("blah", pgmconfig.ProgramName) {
t.Fatalf("unexpected config dir: %s", s)
}
}

View File

@@ -1,179 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package execplugin_test
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/internal/loadertest"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/plugins/config"
. "sigs.k8s.io/kustomize/api/plugins/execplugin"
"sigs.k8s.io/kustomize/api/plugins/loader"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
func TestExecPluginConfig(t *testing.T) {
path := "/app"
rf := resmap.NewFactory(
resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
ldr := loadertest.NewFakeLoader(path)
v := valtest_test.MakeFakeValidator()
pluginConfig := rf.RF().FromMap(
map[string]interface{}{
"apiVersion": "someteam.example.com/v1",
"kind": "SedTransformer",
"metadata": map[string]interface{}{
"name": "some-random-name",
},
"argsOneLiner": "one two",
"argsFromFile": "sed-input.txt",
})
ldr.AddFile("/app/sed-input.txt", []byte(`
s/$FOO/foo/g
s/$BAR/bar/g
\ \ \
`))
p := NewExecPlugin(
loader.AbsolutePluginPath(
config.DefaultPluginConfig(),
pluginConfig.OrgId()))
yaml, err := pluginConfig.AsYAML()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
p.Config(resmap.NewPluginHelpers(ldr, v, rf), yaml)
expected := "/kustomize/plugin/someteam.example.com/v1/sedtransformer/SedTransformer"
if !strings.HasSuffix(p.Path(), expected) {
t.Fatalf("expected suffix '%s', got '%s'", expected, p.Path())
}
expected = `apiVersion: someteam.example.com/v1
argsFromFile: sed-input.txt
argsOneLiner: one two
kind: SedTransformer
metadata:
name: some-random-name
`
if expected != string(p.Cfg()) {
t.Fatalf("expected cfg '%s', got '%s'", expected, string(p.Cfg()))
}
if len(p.Args()) != 5 {
t.Fatalf("unexpected arg len %d, %v", len(p.Args()), p.Args())
}
if p.Args()[0] != "one" ||
p.Args()[1] != "two" ||
p.Args()[2] != "s/$FOO/foo/g" ||
p.Args()[3] != "s/$BAR/bar/g" ||
p.Args()[4] != "\\ \\ \\ " {
t.Fatalf("unexpected arg array: %v", p.Args())
}
}
func makeConfigMap(rf *resource.Factory, name, behavior string, hashValue *string) *resource.Resource {
r := rf.FromMap(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
})
annotations := map[string]string{}
if behavior != "" {
annotations[BehaviorAnnotation] = behavior
}
if hashValue != nil {
annotations[HashAnnotation] = *hashValue
}
if len(annotations) > 0 {
r.SetAnnotations(annotations)
}
return r
}
func makeConfigMapOptions(rf *resource.Factory, name, behavior string, disableHash bool) *resource.Resource {
return rf.FromMapAndOption(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
}, &types.GeneratorArgs{Behavior: behavior}, &types.GeneratorOptions{DisableNameSuffixHash: disableHash})
}
func strptr(s string) *string {
return &s
}
func TestUpdateResourceOptions(t *testing.T) {
p := NewExecPlugin("")
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
in := resmap.New()
expected := resmap.New()
cases := []struct {
behavior string
needsHash bool
hashValue *string
}{
{hashValue: strptr("false")},
{hashValue: strptr("true"), needsHash: true},
{behavior: "replace"},
{behavior: "merge"},
{behavior: "create"},
{behavior: "nonsense"},
{behavior: "merge", hashValue: strptr("false")},
{behavior: "merge", hashValue: strptr("true"), needsHash: true},
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in.Append(makeConfigMap(rf, name, c.behavior, c.hashValue))
expected.Append(makeConfigMapOptions(rf, name, c.behavior, !c.needsHash))
}
actual, err := p.UpdateResourceOptions(in)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
for i, a := range expected.Resources() {
b := actual.GetByIndex(i)
if b == nil {
t.Fatalf("resource %d missing from processed map", i)
}
if !a.Equals(b) {
t.Errorf("expected %v got %v", a, b)
}
if a.NeedHashSuffix() != b.NeedHashSuffix() {
t.Errorf("")
}
if a.Behavior() != b.Behavior() {
t.Errorf("expected %v got %v", a.Behavior(), b.Behavior())
}
}
}
func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
p := NewExecPlugin("")
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
cases := []string{
"",
"FaLsE",
"TrUe",
"potato",
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in := resmap.New()
in.Append(makeConfigMap(rf, name, "", &c))
_, err := p.UpdateResourceOptions(in)
if err == nil {
t.Errorf("expected error from value %q", c)
}
}
}

View File

@@ -1,54 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package provenance
import (
"fmt"
"io"
"runtime"
)
var (
version = "unknown"
// sha1 from git, output of $(git rev-parse HEAD)
gitCommit = "$Format:%H$"
// build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
buildDate = "1970-01-01T00:00:00Z"
goos = runtime.GOOS
goarch = runtime.GOARCH
)
// Provenance holds information about the build of an executable.
type Provenance struct {
// Version of the kustomize binary.
Version string `json:"version"`
// GitCommit is a git commit
GitCommit string `json:"gitCommit"`
// BuildDate is date of the build.
BuildDate string `json:"buildDate"`
// GoOs holds OS name.
GoOs string `json:"goOs"`
// GoArch holds architecture name.
GoArch string `json:"goArch"`
}
// GetProvenance returns an instance of Provenance.
func GetProvenance() Provenance {
return Provenance{
version,
gitCommit,
buildDate,
goos,
goarch,
}
}
// Print prints provenance info.
func (v Provenance) Print(w io.Writer, short bool) {
if short {
fmt.Fprintf(w, "%s\n", v.Version)
} else {
fmt.Fprintf(w, "Version: %+v\n", v)
}
}

View File

@@ -1,15 +0,0 @@
/// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package patch holds miscellaneous interfaces used by kustomize.
package resmap
import (
"sigs.k8s.io/kustomize/api/resource"
)
// PatchFactory makes transformers that require k8sdeps.
type PatchFactory interface {
MergePatches(patches []*resource.Resource,
rf *resource.Factory) (ResMap, error)
}

View File

@@ -1,199 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Here is a structure of a kustomization of two components, component1
// and component2, that both use a shared postgres definition, which
// they would individually adjust. This test case checks that the name
// prefix does not cause a name reference conflict.
//
// root
// / \
// component1/overlay component2/overlay
// | |
// component1/base component2/base
// \ /
// base
//
// This is the directory layout:
//
// ├── component1
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── component2
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── shared
// │ ├── kustomization.yaml
// │ └── resources.yaml
// ├── kustomization.yaml
func TestBaseReuseNameConflict(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app/component1/base", `
resources:
- ../../shared
namePrefix: component1-
`)
th.WriteK("/app/component1/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app/component2/base", `
resources:
- ../../shared
namePrefix: component2-
`)
th.WriteK("/app/component2/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app/shared", `
resources:
- resources.yaml
`)
th.WriteF("/app/shared/resources.yaml", `
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- name: postgres
image: postgres
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
ports:
- name: postgres
containerPort: 5432
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres
`)
th.WriteK("/app", `
resources:
- component1/overlay
- component2/overlay
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: overlay-component1-postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overlay-component1-postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- image: postgres
imagePullPolicy: IfNotPresent
name: postgres
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: overlay-component1-postgres
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: overlay-component2-postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overlay-component2-postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- image: postgres
imagePullPolicy: IfNotPresent
name: postgres
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: overlay-component2-postgres
`)
}

View File

@@ -1,557 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
const httpsService = `
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- port: 443
protocol: TCP
name: https
selector:
app: my-app
`
func writeStatefulSetBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
resources:
- statefulset.yaml
`)
th.WriteF("/app/base/statefulset.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-svc
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-image
volumeClaimTemplates:
- spec:
storageClassName: default
`)
}
func writeHTTPSOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/https", `
resources:
- ../base
- https-svc.yaml
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/https/https-svc.yaml", httpsService)
th.WriteF("/app/https/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
`)
}
func writeHTTPSTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/https/service/https-svc.yaml", httpsService)
th.WriteF("/app/https/transformer/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: svcNameTran
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
`)
}
func writeHTTPSTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/https/service", `
resources:
- https-svc.yaml
`)
th.WriteK("/app/https/transformer", `
resources:
- transformer.yaml
`)
writeHTTPSTransformerRaw(th)
}
func writeConfigFromEnvOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/config", `
resources:
- ../base
configMapGenerator:
- name: my-config
literals:
- MY_ENV=foo
generatorOptions:
disableNameSuffixHash: true
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/config/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: my-config
`)
}
func writeConfigFromEnvTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/config/map/generator.yaml", `
apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: my-config
disableNameSuffixHash: true
literals:
- MY_ENV=foo
`)
th.WriteF("/app/config/transformer/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: envFromConfigTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: my-config
`)
}
func writeConfigFromEnvTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/config/map", `
resources:
- generator.yaml
`)
th.WriteK("/app/config/transformer", `
resources:
- transformer.yaml
`)
writeConfigFromEnvTransformerRaw(th)
}
func writeTolerationsOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tolerations", `
resources:
- ../base
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/tolerations/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
`)
}
func writeTolerationsTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/tolerations/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: tolTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
`)
}
func writeTolerationsTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tolerations", `
resources:
- transformer.yaml
`)
writeTolerationsTransformerRaw(th)
}
func writeStorageOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/storage", `
resources:
- ../base
patchesJson6902:
- target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
path: sts-patch.json
`)
th.WriteF("/app/storage/sts-patch.json", `
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
`)
}
func writeStorageTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/storage/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: storageTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
`)
}
func writeStorageTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/storage", `
resources:
- transformer.yaml
`)
writeStorageTransformerRaw(th)
}
func writePatchingOverlays(th *kusttest_test.KustTestHarness) {
writeStorageOverlay(th)
writeConfigFromEnvOverlay(th)
writeTolerationsOverlay(th)
writeHTTPSOverlay(th)
}
func writePatchingTransformersRaw(th *kusttest_test.KustTestHarness) {
writeStorageTransformerRaw(th)
writeConfigFromEnvTransformerRaw(th)
writeTolerationsTransformerRaw(th)
writeHTTPSTransformerRaw(th)
}
// Similar to writePatchingTransformersRaw, except here the
// transformers and related artifacts are addressable as _bases_.
// They are listed in a kustomization file, and consumers of
// the plugin refer to the kustomization instead of to the local
// file in the "transformers:" field.
//
// Using bases makes the set of files relocatable with
// respect to the overlays, and avoids the need to relax load
// restrictions on file paths reaching outside the `dev` and
// `prod` kustomization roots. I.e. with bases tests can use
// NewKustTestHarness instead of NewKustTestHarnessNoLoadRestrictor.
//
// Using transformer plugins from _bases_ means the plugin config
// must be self-contained, i.e. the config may not have fields that
// refer to local files, since those files won't be present when
// the plugin is instantiated and used.
func writePatchingTransformerBases(th *kusttest_test.KustTestHarness) {
writeStorageTransformerBase(th)
writeConfigFromEnvTransformerBase(th)
writeTolerationsTransformerBase(th)
writeHTTPSTransformerBase(th)
}
// Here's a complex kustomization scenario that combines multiple overlays
// on a common base:
//
// dev prod
// | |
// | |
// + ------- + + ------------ + ------------- +
// | | | | |
// | | | | |
// v | v v v
// storage + -----> config tolerations https
// | | | |
// | | | |
// | + --- + + --- + |
// | | | |
// | v v |
// + -----------------------> base <------------------ +
//
// The base resource is a statefulset. Each intermediate overlay manages or
// generates new resources and patches different aspects of the same base
// resource, without using any of the `namePrefix`, `nameSuffix` or `namespace`
// kustomization keywords.
//
// Intermediate overlays:
// - storage: Changes the storage class of the stateful set with a JSON patch.
// - config: Generates a config map and adds a field as an environment
// variable.
// - tolerations: Adds a new tolerations field in the spec.
// - https: Adds a new service resource and changes the service name in the
// stateful set.
//
// Top overlays:
// - dev: Combines the storage and config intermediate overlays.
// - prod: Combines the config, tolerations and https intermediate overlays.
func TestComplexComposition_Dev_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingOverlays(th)
th.WriteK("/app/dev", `
resources:
- ../storage
- ../config
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}
}
const devDesiredResult = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
selector:
matchLabels:
app: my-app
serviceName: my-svc
template:
metadata:
labels:
app: my-app
spec:
containers:
- envFrom:
- configMapRef:
name: my-config
image: my-image
name: app
volumeClaimTemplates:
- spec:
storageClassName: my-sc
---
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
`
func TestComplexComposition_Dev_SuccessWithRawTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingTransformersRaw(th)
th.WriteK("/app/dev", `
resources:
- ../base
generators:
- ../config/map/generator.yaml
transformers:
- ../config/transformer/transformer.yaml
- ../storage/transformer.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, devDesiredResult)
}
func TestComplexComposition_Dev_SuccessWithBaseTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingTransformerBases(th)
th.WriteK("/app/dev", `
resources:
- ../base
generators:
- ../config/map
transformers:
- ../config/transformer
- ../storage
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, devDesiredResult)
}
func TestComplexComposition_Prod_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingOverlays(th)
th.WriteK("/app/prod", `
resources:
- ../config
- ../tolerations
- ../https
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}
}
const prodDesiredResult = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
selector:
matchLabels:
app: my-app
serviceName: my-https-svc
template:
metadata:
labels:
app: my-app
spec:
containers:
- envFrom:
- configMapRef:
name: my-config
image: my-image
name: app
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
volumeClaimTemplates:
- spec:
storageClassName: default
---
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- name: https
port: 443
protocol: TCP
selector:
app: my-app
---
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
`
func TestComplexComposition_Prod_SuccessWithRawTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingTransformersRaw(th)
th.WriteK("/app/prod", `
resources:
- ../base
- ../https/service/https-svc.yaml
generators:
- ../config/map/generator.yaml
transformers:
- ../config/transformer/transformer.yaml
- ../https/transformer/transformer.yaml
- ../tolerations/transformer.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDesiredResult)
}
func TestComplexComposition_Prod_SuccessWithBaseTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingTransformerBases(th)
th.WriteK("/app/prod", `
resources:
- ../base
- ../https/service
generators:
- ../config/map
transformers:
- ../config/transformer
- ../https/transformer
- ../tolerations
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDesiredResult)
}

View File

@@ -1,216 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Demo custom configuration of a builtin transformation.
// This is a NamePrefixer that only touches Deployments
// and Services.
func TestCustomNamePrefixer(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PrefixSuffixTransformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app")
th.WriteK("/app", `
resources:
- deployment.yaml
- role.yaml
- service.yaml
transformers:
- prefixer.yaml
`)
th.WriteF("/app/prefixer.yaml", `
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
name: customPrefixer
prefix: zzz-
fieldSpecs:
- kind: Deployment
path: metadata/name
- kind: Service
path: metadata/name
`)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
th.WriteF("/app/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: zzz-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Role
metadata:
name: myRole
---
apiVersion: v1
kind: Service
metadata:
name: zzz-myService
`)
}
// Demo custom configuration as a base.
func TestReusableCustomNamePrefixer(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PrefixSuffixTransformer")
tc.BuildGoPlugin(
"builtin", "", "LabelTransformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/foo")
// This kustomization file contains resources that
// all happen to be plugin configurations. This makes
// these plugins all available as part of a base,
// re-usable in any number of other kustomizations.
// Just specify the path (or URL) to this base in the
// "transformers:" field (not the "resources" field).
th.WriteK("/app/mytransformers", `
resources:
- prefixer.yaml
- labeller.yaml
`)
th.WriteF("/app/mytransformers/prefixer.yaml", `
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
name: myPrefixer
prefix: zzz-
fieldSpecs:
- kind: Deployment
path: metadata/name
- kind: Service
path: metadata/name
`)
th.WriteF("/app/mytransformers/labeller.yaml", `
apiVersion: builtin
kind: LabelTransformer
metadata:
name: myLabeller
labels:
company: acmeCorp
fieldSpecs:
- path: spec/template/metadata/labels
kind: Deployment
`)
th.WriteK("/app/foo", `
resources:
- deployment.yaml
- role.yaml
- service.yaml
transformers:
- ../mytransformers
`)
th.WriteF("/app/foo/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
th.WriteF("/app/foo/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/foo/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: zzz-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
company: acmeCorp
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Role
metadata:
name: myRole
---
apiVersion: v1
kind: Service
metadata:
name: zzz-myService
`)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,244 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func makeResourcesForPatchTest(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
volumes:
- name: nginx-persistent-storage
emptyDir: {}
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestStrategicMergePatchInline(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestJSONPatchInline(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: nginx
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestExtendedPatchInlineJSON(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patches:
- target:
kind: Deployment
name: nginx
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestExtendedPatchInlineYAML(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patches:
- target:
kind: Deployment
name: nginx
patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}

View File

@@ -1,297 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target
import (
"sigs.k8s.io/kustomize/api/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
)
// Functions dedicated to configuring the builtin
// transformer and generator plugins using config data
// read from a kustomization file and from the
// config.TransformerConfig, whose data may be a
// mix of hardcoded values and data read from file.
//
// Non-builtin plugins will get their configuration
// from their own dedicated structs and YAML files.
//
// There are some loops in the functions below because
// the kustomization file would, say, allow someone to
// request multiple secrets be made, or run multiple
// image tag transforms. In these cases, we'll need
// N plugin instances with differing configurations.
func (kt *KustTarget) configureBuiltinGenerators() (
result []resmap.Generator, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.ConfigMapGenerator,
builtinhelpers.SecretGenerator,
} {
r, err := generatorConfigurators[bpt](
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
if err != nil {
return nil, err
}
result = append(result, r...)
}
return result, nil
}
func (kt *KustTarget) configureBuiltinTransformers(
tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.PatchStrategicMergeTransformer,
builtinhelpers.PatchTransformer,
builtinhelpers.NamespaceTransformer,
builtinhelpers.PrefixSuffixTransformer,
builtinhelpers.LabelTransformer,
builtinhelpers.AnnotationsTransformer,
builtinhelpers.PatchJson6902Transformer,
builtinhelpers.ReplicaCountTransformer,
builtinhelpers.ImageTagTransformer,
} {
r, err := transformerConfigurators[bpt](
kt, bpt, builtinhelpers.TransformerFactories[bpt], tc)
if err != nil {
return nil, err
}
result = append(result, r...)
}
return result, nil
}
type gFactory func() resmap.GeneratorPlugin
var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
kt *KustTarget,
bpt builtinhelpers.BuiltinPluginType,
factory gFactory) (result []resmap.Generator, err error){
builtinhelpers.SecretGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.SecretArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.SecretGenerator {
c.SecretArgs = args
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.ConfigMapGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.ConfigMapArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.ConfigMapGenerator {
c.ConfigMapArgs = args
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
}
type tFactory func() resmap.TransformerPlugin
var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
kt *KustTarget,
bpt builtinhelpers.BuiltinPluginType,
f tFactory,
tc *builtinconfig.TransformerConfig) (result []resmap.Transformer, err error){
builtinhelpers.NamespaceTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
FieldSpecs []types.FieldSpec
}
c.Namespace = kt.kustomization.Namespace
c.FieldSpecs = tc.NameSpace
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PatchJson6902Transformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
}
for _, args := range kt.kustomization.PatchesJson6902 {
c.Target = *args.Target
c.Path = args.Path
c.JsonOp = args.Patch
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.PatchStrategicMergeTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
return
}
var c struct {
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
}
c.Paths = kt.kustomization.PatchesStrategicMerge
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PatchTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
if len(kt.kustomization.Patches) == 0 {
return
}
var c struct {
Path string `json:"path,omitempty" yaml:"path,omitempty"`
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
}
for _, pc := range kt.kustomization.Patches {
c.Target = pc.Target
c.Patch = pc.Patch
c.Path = pc.Path
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.LabelTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Labels map[string]string
FieldSpecs []types.FieldSpec
}
c.Labels = kt.kustomization.CommonLabels
c.FieldSpecs = tc.CommonLabels
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.AnnotationsTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Annotations map[string]string
FieldSpecs []types.FieldSpec
}
c.Annotations = kt.kustomization.CommonAnnotations
c.FieldSpecs = tc.CommonAnnotations
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PrefixSuffixTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Prefix string
Suffix string
FieldSpecs []types.FieldSpec
}
c.Prefix = kt.kustomization.NamePrefix
c.Suffix = kt.kustomization.NameSuffix
c.FieldSpecs = tc.NamePrefix
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.ImageTagTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
ImageTag types.Image
FieldSpecs []types.FieldSpec
}
for _, args := range kt.kustomization.Images {
c.ImageTag = args
c.FieldSpecs = tc.Images
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.ReplicaCountTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Replica types.Replica
FieldSpecs []types.FieldSpec
}
for _, args := range kt.kustomization.Replicas {
c.Replica = args
c.FieldSpecs = tc.Replicas
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
}

View File

@@ -1,602 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNamespacedSecrets(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteF("/app/secrets.yaml", `
apiVersion: v1
kind: Secret
metadata:
name: dummy
namespace: default
type: Opaque
data:
dummy: ""
---
apiVersion: v1
kind: Secret
metadata:
name: dummy
namespace: kube-system
type: Opaque
data:
dummy: ""
`)
// This should find the proper secret.
th.WriteF("/app/role.yaml", `
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dummy
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["dummy"]
verbs: ["get"]
`)
th.WriteK("/app", `
resources:
- secrets.yaml
- role.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
// This validates Fix #1444. This should not be an error anymore -
// the secrets have the same name but are in different namespaces.
// The ClusterRole (by def) is not in a namespace,
// an in this case applies to *any* Secret resource
// named "dummy"
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: default
type: Opaque
---
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: kube-system
type: Opaque
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dummy
rules:
- apiGroups:
- ""
resourceNames:
- dummy
resources:
- secrets
verbs:
- get
`)
}
// TestNameAndNsTransformation validates that NamespaceTransformer,
// PrefixSuffixTransformer and namereference transformers are
// able to deal with simultaneous change of namespace and name.
func TestNameAndNsTransformation(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/nameandns")
th.WriteK("/nameandns", `
namePrefix: p1-
nameSuffix: -s1
namespace: newnamespace
resources:
- resources.yaml
`)
th.WriteF("/nameandns/resources.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: cm1
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cm2
namespace: ns1
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: ns1
---
apiVersion: v1
kind: Service
metadata:
name: svc2
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa1
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa2
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
subjects:
- kind: ServiceAccount
name: sa1
namespace: ns1
- kind: ServiceAccount
name: sa2
namespace: ns1
- kind: ServiceAccount
name: sa3
namespace: random
- kind: ServiceAccount
name: default
namespace: irrelevant
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: example
webhooks:
- name: example1
clientConfig:
service:
name: svc1
namespace: ns1
- name: example2
clientConfig:
service:
name: svc2
namespace: ns1
- name: example3
clientConfig:
service:
name: svc3
namespace: random
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
kind: ClusterRole
metadata:
name: cr1
---
kind: ClusterRoleBinding
metadata:
name: crb1
subjects:
- kind: ServiceAccount
name: default
namespace: irrelevant
---
kind: PersistentVolume
metadata:
name: pv1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: ConfigMap
metadata:
name: p1-cm1-s1
namespace: newnamespace
---
apiVersion: v1
kind: ConfigMap
metadata:
name: p1-cm2-s1
namespace: newnamespace
---
apiVersion: v1
kind: Service
metadata:
name: p1-svc1-s1
namespace: newnamespace
---
apiVersion: v1
kind: Service
metadata:
name: p1-svc2-s1
namespace: newnamespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: p1-sa1-s1
namespace: newnamespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: p1-sa2-s1
namespace: newnamespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: p1-manager-rolebinding-s1
subjects:
- kind: ServiceAccount
name: p1-sa1-s1
namespace: newnamespace
- kind: ServiceAccount
name: p1-sa2-s1
namespace: newnamespace
- kind: ServiceAccount
name: sa3
namespace: random
- kind: ServiceAccount
name: default
namespace: newnamespace
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: p1-example-s1
webhooks:
- clientConfig:
service:
name: p1-svc1-s1
namespace: newnamespace
name: example1
- clientConfig:
service:
name: p1-svc2-s1
namespace: newnamespace
name: example2
- clientConfig:
service:
name: svc3
namespace: random
name: example3
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
kind: ClusterRole
metadata:
name: p1-cr1-s1
---
kind: ClusterRoleBinding
metadata:
name: p1-crb1-s1
subjects:
- kind: ServiceAccount
name: default
namespace: newnamespace
---
kind: PersistentVolume
metadata:
name: p1-pv1-s1
`)
}
// This serie of constants is used to prove the need of
// the namespace field in the objref field of the var declaration.
// The following tests demonstrate that it creates umbiguous variable
// declaration if two entities of the kind with the same name
// but in different namespaces are declared.
// This is tracking the following issue:
// https://github.com/kubernetes-sigs/kustomize/issues/1298
const namespaceNeedInVarMyApp string = `
resources:
- elasticsearch-dev-service.yaml
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
const namespaceNeedInVarDevResources string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: dev
spec:
template:
spec:
containers:
- name: elasticsearch
env:
- name: DISCOVERY_SERVICE
value: "$(elasticsearch-dev-service-name).monitoring.svc.cluster.local"
- name: DISCOVERY_PROTOCOL
value: "$(elasticsearch-dev-protocol)"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: dev
spec:
ports:
- name: transport
port: 9300
protocol: TCP
clusterIP: None
`
const namespaceNeedInVarTestResources string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: test
spec:
template:
spec:
containers:
- name: elasticsearch
env:
- name: DISCOVERY_SERVICE
value: "$(elasticsearch-test-service-name).monitoring.svc.cluster.local"
- name: DISCOVERY_PROTOCOL
value: "$(elasticsearch-test-protocol)"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: test
spec:
ports:
- name: transport
port: 9300
protocol: UDP
clusterIP: None
`
const namespaceNeedInVarExpectedOutput string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: dev
spec:
template:
spec:
containers:
- env:
- name: DISCOVERY_SERVICE
value: elasticsearch.monitoring.svc.cluster.local
- name: DISCOVERY_PROTOCOL
value: TCP
name: elasticsearch
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: dev
spec:
clusterIP: None
ports:
- name: transport
port: 9300
protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: test
spec:
template:
spec:
containers:
- env:
- name: DISCOVERY_SERVICE
value: elasticsearch.monitoring.svc.cluster.local
- name: DISCOVERY_PROTOCOL
value: UDP
name: elasticsearch
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: test
spec:
clusterIP: None
ports:
- name: transport
port: 9300
protocol: UDP
`
// TestVariablesAmbiguous demonstrates how two variables pointing at two different resources
// using the same name in different namespaces are treated as ambiguous if the namespace is
// not specified
func TestVariablesAmbiguous(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyApp)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(), "unable to disambiguate") {
t.Fatalf("unexpected error %v", err)
}
}
const namespaceNeedInVarDevFolder string = `
resources:
- elasticsearch-dev-service.yaml
vars:
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
const namespaceNeedInVarTestFolder string = `
resources:
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
// TestVariablesAmbiguousWorkaround demonstrates a possible workaround
// to TestVariablesAmbiguous problem. It requires to separate the variables
// and resources into multiple kustomization context/folders instead of one.
func TestVariablesAmbiguousWorkaround(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/workaround")
th.WriteK("/namespaceNeedInVar/dev", namespaceNeedInVarDevFolder)
th.WriteF("/namespaceNeedInVar/dev/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteK("/namespaceNeedInVar/test", namespaceNeedInVarTestFolder)
th.WriteF("/namespaceNeedInVar/test/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
th.WriteK("/namespaceNeedInVar/workaround", `
resources:
- ../dev
- ../test
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
}
const namespaceNeedInVarMyAppWithNamespace string = `
resources:
- elasticsearch-dev-service.yaml
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
namespace: test
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
namespace: test
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
namespace: dev
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
namespace: dev
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
// TestVariablesDisambiguatedWithNamespace demonstrates that adding the namespace
// to the variable declarations allows to disambiguate the variables.
func TestVariablesDisambiguatedWithNamespace(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyAppWithNamespace)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
}

View File

@@ -1,64 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package transform
import (
"errors"
"fmt"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
)
// mapTransformer applies a string->string map to fieldSpecs.
type mapTransformer struct {
m map[string]string
fieldSpecs []types.FieldSpec
}
var _ resmap.Transformer = &mapTransformer{}
// NewMapTransformer construct a mapTransformer.
func NewMapTransformer(
pc []types.FieldSpec, m map[string]string) (resmap.Transformer, error) {
if m == nil {
return newNoOpTransformer(), nil
}
if pc == nil {
return nil, errors.New("fieldSpecs is not expected to be nil")
}
return &mapTransformer{fieldSpecs: pc, m: m}, nil
}
// Transform apply each <key, value> pair in the mapTransformer to the
// fields specified in mapTransformer.
func (o *mapTransformer) Transform(m resmap.ResMap) error {
for _, r := range m.Resources() {
for _, path := range o.fieldSpecs {
if !r.OrgId().IsSelected(&path.Gvk) {
continue
}
err := MutateField(
r.Map(), path.PathSlice(),
path.CreateIfNotPresent, o.addMap)
if err != nil {
return err
}
}
}
return nil
}
func (o *mapTransformer) addMap(in interface{}) (interface{}, error) {
m, ok := in.(map[string]interface{})
if in == nil {
m = map[string]interface{}{}
} else if !ok {
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
for k, v := range o.m {
m[k] = v
}
return m, nil
}

View File

@@ -1,21 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package transform
import "sigs.k8s.io/kustomize/api/resmap"
// noOpTransformer contains a no-op transformer.
type noOpTransformer struct{}
var _ resmap.Transformer = &noOpTransformer{}
// newNoOpTransformer constructs a noOpTransformer.
func newNoOpTransformer() resmap.Transformer {
return &noOpTransformer{}
}
// Transform does nothing.
func (o *noOpTransformer) Transform(_ resmap.ResMap) error {
return nil
}

View File

@@ -1,10 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// ConfigMapArgs contains the metadata of how to generate a configmap.
type ConfigMapArgs struct {
// GeneratorArgs for the configmap.
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
}

View File

@@ -1,9 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package types holds the definition of the kustomization struct and
// supporting structs. It's the k8s API conformant object that describes
// a set of generation and transformation operations to create and/or
// modify k8s resources.
// A kustomization file is a serialization of this struct.
package types

View File

@@ -1,51 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
import (
"log"
"regexp"
"sigs.k8s.io/yaml"
)
// FixKustomizationPreUnmarshalling modies the raw data
// before marshalling - e.g. changes old field names to
// new field names.
func FixKustomizationPreUnmarshalling(data []byte) []byte {
deprecateFieldsMap := map[string]string{
"imageTags:": "images:",
}
for oldname, newname := range deprecateFieldsMap {
pattern := regexp.MustCompile(oldname)
data = pattern.ReplaceAll(data, []byte(newname))
}
if useLegacyPatch(data) {
pattern := regexp.MustCompile("patches:")
data = pattern.ReplaceAll(data, []byte("patchesStrategicMerge:"))
}
return data
}
func useLegacyPatch(data []byte) bool {
found := false
var object map[string]interface{}
err := yaml.Unmarshal(data, &object)
if err != nil {
log.Fatalf("invalid content from %s\n", string(data))
}
if rawPatches, ok := object["patches"]; ok {
patches, ok := rawPatches.([]interface{})
if !ok {
log.Fatalf("invalid patches from %v\n", rawPatches)
}
for _, p := range patches {
_, ok := p.(string)
if ok {
found = true
}
}
}
return found
}

View File

@@ -1,12 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
//go:generate stringer -type=GarbagePolicy
type GarbagePolicy int
const (
GarbageIgnore GarbagePolicy = iota + 1
GarbageCollect
)

View File

@@ -1,37 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types_test
import (
"testing"
. "sigs.k8s.io/kustomize/api/types"
)
func TestGenArgs_String(t *testing.T) {
tests := []struct {
ga *GenArgs
expected string
}{
{
ga: nil,
expected: "{nilGenArgs}",
},
{
ga: &GenArgs{},
expected: "{nsfx:false,beh:unspecified}",
},
{
ga: NewGenArgs(
&GeneratorArgs{Behavior: "merge"},
&GeneratorOptions{DisableNameSuffixHash: false}),
expected: "{nsfx:true,beh:merge}",
},
}
for _, test := range tests {
if test.ga.String() != test.expected {
t.Fatalf("Expected '%s', got '%s'", test.expected, test.ga.String())
}
}
}

View File

@@ -1,24 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
type GeneratorArgs struct {
// Namespace for the configmap, optional
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// Name - actually the partial name - of the generated resource.
// The full name ends up being something like
// NamePrefix + this.Name + hash(content of generated resource).
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Behavior of generated resource, must be one of:
// 'create': create a new one
// 'replace': replace the existing one
// 'merge': merge with the existing one
Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"`
// KvPairSources for the generator.
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
}

View File

@@ -1,18 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
type GeneratorOptions struct {
// Labels to add to all generated resources.
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Annotations to add to all generated resources.
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
// DisableNameSuffixHash if true disables the default behavior of adding a
// suffix to the names of generated resources that is a hash of the
// resource contents.
DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"`
}

View File

@@ -1,21 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// Image contains an image name, a new name, a new tag or digest,
// which will replace the original name and tag.
type Image struct {
// Name is a tag-less image name.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// NewName is the value used to replace the original name.
NewName string `json:"newName,omitempty" yaml:"newName,omitempty"`
// NewTag is the value used to replace the original tag.
NewTag string `json:"newTag,omitempty" yaml:"newTag,omitempty"`
// Digest is the value used to replace the original image tag.
// If digest is present NewTag value is ignored.
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
}

View File

@@ -1,16 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// Inventory records all objects touched in a build operation.
type Inventory struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`
ConfigMap NameArgs `json:"configMap,omitempty" yaml:"configMap,omitempty"`
}
// NameArgs holds both namespace and name.
type NameArgs struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}

View File

@@ -1,151 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
const (
KustomizationVersion = "kustomize.config.k8s.io/v1beta1"
KustomizationKind = "Kustomization"
)
// Kustomization holds the information needed to generate customized k8s api resources.
type Kustomization struct {
TypeMeta `json:",inline" yaml:",inline"`
//
// Operators - what kustomize can do.
//
// NamePrefix will prefix the names of all resources mentioned in the kustomization
// file including generated configmaps and secrets.
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
// NameSuffix will suffix the names of all resources mentioned in the kustomization
// file including generated configmaps and secrets.
NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
// Namespace to add to all objects.
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// CommonLabels to add to all objects and selectors.
CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
// CommonAnnotations to add to all objects.
CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
// PatchesStrategicMerge specifies the relative path to a file
// containing a strategic merge patch. Format documented at
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
// URLs and globs are not supported.
PatchesStrategicMerge []PatchStrategicMerge `json:"patchesStrategicMerge,omitempty" yaml:"patchesStrategicMerge,omitempty"`
// JSONPatches is a list of JSONPatch for applying JSON patch.
// Format documented at https://tools.ietf.org/html/rfc6902
// and http://jsonpatch.com
PatchesJson6902 []PatchJson6902 `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
// Patches is a list of patches, where each one can be either a
// Strategic Merge Patch or a JSON patch.
// Each patch can be applied to multiple target objects.
Patches []Patch `json:"patches,omitempty" yaml:"patches,omitempty"`
// Images is a list of (image name, new name, new tag or digest)
// for changing image names, tags or digests. This can also be achieved with a
// patch, but this operator is simpler to specify.
Images []Image `json:"images,omitempty" yaml:"images,omitempty"`
// Replicas is a list of {resourcename, count} that allows for simpler replica
// specification. This can also be done with a patch.
Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"`
// Vars allow things modified by kustomize to be injected into a
// kubernetes object specification. A var is a name (e.g. FOO) associated
// with a field in a specific resource instance. The field must
// contain a value of type string/bool/int/float, and defaults to the name field
// of the instance. Any appearance of "$(FOO)" in the object
// spec will be replaced at kustomize build time, after the final
// value of the specified field has been determined.
Vars []Var `json:"vars,omitempty" yaml:"vars,omitempty"`
//
// Operands - what kustomize operates on.
//
// Resources specifies relative paths to files holding YAML representations
// of kubernetes API objects, or specifcations of other kustomizations
// via relative paths, absolute paths, or URLs.
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
// Crds specifies relative paths to Custom Resource Definition files.
// This allows custom resources to be recognized as operands, making
// it possible to add them to the Resources list.
// CRDs themselves are not modified.
Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"`
// Deprecated.
// Anything that would have been specified here should
// be specified in the Resources field instead.
Bases []string `json:"bases,omitempty" yaml:"bases,omitempty"`
//
// Generators (operators that create operands)
//
// ConfigMapGenerator is a list of configmaps to generate from
// local data (one configMap per list item).
// The resulting resource is a normal operand, subject to
// name prefixing, patching, etc. By default, the name of
// the map will have a suffix hash generated from its contents.
ConfigMapGenerator []ConfigMapArgs `json:"configMapGenerator,omitempty" yaml:"configMapGenerator,omitempty"`
// SecretGenerator is a list of secrets to generate from
// local data (one secret per list item).
// The resulting resource is a normal operand, subject to
// name prefixing, patching, etc. By default, the name of
// the map will have a suffix hash generated from its contents.
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
// Configurations is a list of transformer configuration files
Configurations []string `json:"configurations,omitempty" yaml:"configurations,omitempty"`
// Generators is a list of files containing custom generators
Generators []string `json:"generators,omitempty" yaml:"generators,omitempty"`
// Transformers is a list of files containing transformers
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
// Inventory appends an object that contains the record
// of all other objects, which can be used in apply, prune and delete
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
}
// FixKustomizationPostUnmarshalling fixes things
// like empty fields that should not be empty, or
// moving content of deprecated fields to newer
// fields.
func (k *Kustomization) FixKustomizationPostUnmarshalling() {
if k.APIVersion == "" {
k.APIVersion = KustomizationVersion
}
if k.Kind == "" {
k.Kind = KustomizationKind
}
for _, b := range k.Bases {
k.Resources = append(k.Resources, b)
}
k.Bases = nil
}
func (k *Kustomization) EnforceFields() []string {
var errs []string
if k.APIVersion != "" && k.APIVersion != KustomizationVersion {
errs = append(errs, "apiVersion should be "+KustomizationVersion)
}
if k.Kind != "" && k.Kind != KustomizationKind {
errs = append(errs, "kind should be "+KustomizationKind)
}
return errs
}

View File

@@ -1,31 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// KvPairSources defines places to obtain key value pairs.
type KvPairSources struct {
// LiteralSources is a list of literal
// pair sources. Each literal source should
// be a key and literal value, e.g. `key=value`
LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"`
// FileSources is a list of file "sources" to
// use in creating a list of key, value pairs.
// A source takes the form: [{key}=]{path}
// If the "key=" part is missing, the key is the
// path's basename. If they "key=" part is present,
// it becomes the key (replacing the basename).
// In either case, the value is the file contents.
// Specifying a directory will iterate each named
// file in the directory whose basename is a
// valid configmap key.
FileSources []string `json:"files,omitempty" yaml:"files,omitempty"`
// EnvSources is a list of file paths.
// The contents of each file should be one
// key=value pair per line, e.g. a Docker
// or npm ".env" file or a ".ini" file
// (wikipedia.org/wiki/INI_file)
EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"`
}

View File

@@ -1,11 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta
// No need for a direct dependence; the fields are stable.
type ObjectMeta struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}

View File

@@ -1,10 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// Pair is a key value pair.
type Pair struct {
Key string
Value string
}

View File

@@ -1,19 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// Patch represent either a Strategic Merge Patch or a JSON patch
// and its targets.
// The content of the patch can either be from a file
// or from an inline string.
type Patch struct {
// Path is a relative file path to the patch file.
Path string `json:"path,omitempty" yaml:"path,omitempty"`
// Patch is the content of a patch.
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
// Target points to the resources that the patch is applied to
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
}

View File

@@ -1,21 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// PatchJson6902 represents a json patch for an object
// with format documented https://tools.ietf.org/html/rfc6902.
type PatchJson6902 struct {
// PatchTarget refers to a Kubernetes object that the json patch will be
// applied to. It must refer to a Kubernetes resource under the
// purview of this kustomization. PatchTarget should use the
// raw name of the object (the name specified in its YAML,
// before addition of a namePrefix and a nameSuffix).
Target *PatchTarget `json:"target" yaml:"target"`
// relative file path for a json patch file inside a kustomization
Path string `json:"path,omitempty" yaml:"path,omitempty"`
// inline patch string
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
}

View File

@@ -1,9 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// PatchStrategicMerge represents a relative path to a
// stategic merge patch with the format
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
type PatchStrategicMerge string

View File

@@ -1,15 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
import (
"sigs.k8s.io/kustomize/api/resid"
)
// PatchTarget represents the kubernetes object that the patch is applied to
type PatchTarget struct {
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
Name string `json:"name" yaml:"name"`
}

View File

@@ -1,16 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// PluginConfig holds plugin configuration.
type PluginConfig struct {
// DirectoryPath is an absolute path to a
// directory containing kustomize plugins.
// This directory may contain subdirectories
// further categorizing plugins.
DirectoryPath string
// Enabled is true if plugins are enabled.
Enabled bool
}

View File

@@ -1,16 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// Replica specifies a modification to a replica config.
// The number of replicas of a resource whose name matches will be set to count.
// This struct is used by the ReplicaCountTransform, and is meant to supplement
// the existing patch functionality with a simpler syntax for replica configuration.
type Replica struct {
// The name of the resource to change the replica count
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// The number of replicas required.
Count int64 `json:"count" yaml:"count"`
}

View File

@@ -1,19 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// SecretArgs contains the metadata of how to generate a secret.
type SecretArgs struct {
// GeneratorArgs for the secret.
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
// Type of the secret.
//
// This is the same field as the secret type field in v1/Secret:
// It can be "Opaque" (default), or "kubernetes.io/tls".
//
// If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two
// keys: "tls.key" and "tls.crt"
Type string `json:"type,omitempty" yaml:"type,omitempty"`
}

View File

@@ -1,27 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
import (
"sigs.k8s.io/kustomize/api/resid"
)
// Selector specifies a set of resources.
// Any resource that matches intersection of all conditions
// is included in this set.
type Selector struct {
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// AnnotationSelector is a string that follows the label selection expression
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
// It matches with the resource annotations.
AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"`
// LabelSelector is a string that follows the label selection expression
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
// It matches with the resource labels.
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
}

View File

@@ -1,11 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
// No need for a direct dependence; the fields are stable.
type TypeMeta struct {
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
}

View File

@@ -1,13 +1,12 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// The kustomize CLI.
package main
import (
"os"
"sigs.k8s.io/kustomize/kustomize/internal/commands"
"sigs.k8s.io/kustomize/v3/pkg/commands"
)
func main() {

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// A code generator. See /plugin/doc.go for an explanation.
// See /plugin/doc.go for an explanation.
package main
import (
@@ -12,22 +12,10 @@ import (
"path/filepath"
"strings"
"sigs.k8s.io/kustomize/api/pgmconfig"
"sigs.k8s.io/kustomize/api/plugins/config"
"sigs.k8s.io/kustomize/api/provenance"
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
//go:generate stringer -type=pluginType
type pluginType int
const (
unknown pluginType = iota
Transformer
Generator
)
const packageForGeneratedCode = "builtins"
func main() {
root := inputFileRoot()
file, err := os.Open(root + ".go")
@@ -46,51 +34,29 @@ func main() {
fmt.Sprintf(
"// Code generated by pluginator on %s; DO NOT EDIT.",
root))
w.write(
fmt.Sprintf(
"// pluginator %+v\n", provenance.GetProvenance()))
w.write("\n")
w.write("package " + packageForGeneratedCode)
pType := unknown
w.write("package builtin")
for scanner.Scan() {
l := scanner.Text()
if strings.HasPrefix(l, "//go:generate") {
continue
}
if strings.HasPrefix(l, "//noinspection") {
if l == "var "+plugins.PluginSymbol+" plugin" {
w.write("func New" + root + "Plugin() *" + root + "Plugin {")
w.write(" return &" + root + "Plugin{}")
w.write("}")
continue
}
if l == "var "+config.PluginSymbol+" plugin" {
continue
}
if strings.Contains(l, " Transform(") {
if pType != unknown {
log.Fatal("unexpected Transform(")
}
pType = Transformer
} else if strings.Contains(l, " Generate(") {
if pType != unknown {
log.Fatal("unexpected Generate(")
}
pType = Generator
}
w.write(l)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
w.write("")
w.write("func New" + root + "Plugin() resmap." + pType.String() + "Plugin {")
w.write(" return &" + root + "Plugin{}")
w.write("}")
}
func inputFileRoot() string {
n := os.Getenv("GOFILE")
if !strings.HasSuffix(n, ".go") {
log.Printf("%+v\n", provenance.GetProvenance())
log.Fatalf("expecting .go suffix on %s", n)
}
return n[:len(n)-len(".go")]
@@ -126,7 +92,8 @@ func makeOutputFileName(root string) string {
"src",
pgmconfig.DomainName,
pgmconfig.ProgramName,
"api", "plugins", packageForGeneratedCode,
pgmconfig.PluginRoot,
"builtin",
root+".go")
}

View File

@@ -28,31 +28,3 @@ To disable this, use v3, and the `load_restrictor` flag:
```
kustomize build --load_restrictor none $target
```
## Some field is not transformed by kustomize
Example: [#1319](https://github.com/kubernetes-sigs/kustomize/issues/1319), [#1322](https://github.com/kubernetes-sigs/kustomize/issues/1322), [#1347](https://github.com/kubernetes-sigs/kustomize/issues/1347) and etc.
The fields transformed by kustomize is configured explicitly in [defaultconfig](https://github.com/kubernetes-sigs/kustomize/tree/master/pkg/transformers/config/defaultconfig). The configuration itself can be customized by including `configurations` in `kustomization.yaml`, e.g.
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configurations:
- kustomizeconfig.yaml
```
The configuration directive allows customization of the following transformers:
```yaml
commonAnnotations: []
commonLabels: []
nameprefix: []
namespace: []
varreference: []
namereference: []
images: []
replicas: []
```
To persist the changes to default configuration, submit a PR like [#1338](https://github.com/kubernetes-sigs/kustomize/pull/1338), [#1348](https://github.com/kubernetes-sigs/kustomize/pull/1348) and etc.

View File

@@ -8,57 +8,30 @@ are available on the [release page].
Or...
## Quickly curl the latest binary
## Quickly curl the latest
```
# pick one
opsys=darwin
opsys=windows
opsys=linux
opsys=linux # or darwin, or windows
curl -s https://api.github.com/repos/kubernetes-sigs/kustomize/releases/latest |\
grep browser_download |\
grep $opsys |\
cut -d '"' -f 4 |\
xargs curl -O -L
mv kustomize_kustomize\.v*_${opsys}_amd64 kustomize
mv kustomize_*_${opsys}_amd64 kustomize
chmod u+x kustomize
```
## Build the kustomize CLI from local source
## Install from the HEAD of master branch
Requires [Go] v1.12 or higher:
<!-- @installkustomize @test -->
```
# Need go 1.13 or higher
unset GOPATH
# see https://golang.org/doc/go1.13#modules
unset GO111MODULES
# clone the repo
git clone git@github.com:kubernetes-sigs/kustomize.git
# get into the repo root
cd kustomize
# Optionally checkout a particular tag if you don't
# want to build at head
git checkout kustomize/v3.2.3
# build the binary
(cd kustomize; go install .)
# run it
~/go/bin/kustomize version
go install sigs.k8s.io/kustomize/v3/cmd/kustomize
```
### Other methods
#### Use go get
This works poorly with existing `Go` package installations at the
moment, since kustomize switched over to Go modules but hasn't
historically followed semver with respect to its API.
This is being [fixed](versioningPolicy.md), after which
`go get` should work correctly.
#### macOS
```

View File

@@ -23,24 +23,7 @@ English | [简体中文](zh/README.md)
## Release notes
* [kustomize/3.2.2](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv3.2.2) - kustomize CLI
moved to depend on kustomize Go API [3.3.0](v3.3.0.md).
* [API 3.3.0](v3.3.0.md) - First release of the kustomize Go API
in a module excluding the `kustomize` CLI. From here on,
the CLI and API will release independently.
* [kustomize/3.2.1](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv3.2.1) - Patch release
of `kustomize` CLI in its own module,
depending on Go API release [3.2.0](v3.2.0.md).
* [3.2.0](v3.2.0.md) - TODO(jingfang)
* [3.1.1](v3.1.0.md) - TODO(jingfang)
* [3.1](v3.1.0.md) - Late July 2019. Extended patches and improved resource matching.
* [3.0](v3.0.0.md) - Late June 2019. Plugin developer release.
* [3.0](v3.0.0.md) - Late June 2019. Plugin developer release.
* [2.1](v2.1.0.md) - 18 June 2019. Plugins, ordered resources, etc.

View File

@@ -1,37 +0,0 @@
# kustomization authoring
kustomize provides sub-commands for managing the contents of a kustomization file from the command line.
## kustomize create
The `kustomize create` command will create a new kustomization in the current directory.
When run without any flags the command will create an empty `kustomization.yaml` file that can then be updated manually or with the `kustomize edit` sub-commands.
```
kustomize create --namespace=myapp --resources=deployment.yaml,service.yaml --label=app=myapp
```
### Detecting resources
> NOTE: Resource detection will not follow symlinks.
Flags:
--annotation string Add one or more common annotations.
--autodetect Search for kubernetes resources in the current directory to be added to the kustomization file.
-h, --help help for create
--label string Add one or more common labels.
--nameprefix string Sets the value of the namePrefix field in the kustomization file.
--namespace string Set the value of the namespace field in the customization file.
--namesuffix string Sets the value of the nameSuffix field in the kustomization file.
--recursive Enable recursive directory searching for resource auto-detection.
--resources string Name of a file containing a file to add to the kustomization file.
## kustomize edit
With an existing kustomization file the `kustomize edit` command
* add
* set
* remove
* fix

View File

@@ -1,19 +1,5 @@
# Kustomization File Fields
[field-name-namespace]: plugins/builtins.md#field-name-namespace
[field-name-images]: plugins/builtins.md#field-name-images
[field-name-namePrefix]: plugins/builtins.md#field-name-prefix
[field-name-nameSuffix]: plugins/builtins.md#field-name-prefix
[field-name-patches]: plugins/builtins.md#field-name-patches
[field-name-patchesStrategicMerge]: plugins/builtins.md#field-name-patchesStrategicMerge
[field-name-patchesJson6902]: plugins/builtins.md#field-name-patchesJson6902
[field-name-replicas]: plugins/builtins.md#field-name-replicas
[field-name-secretGenerator]: plugins/builtins.md#field-name-secretGenerator
[field-name-commonLabels]: plugins/builtins.md#field-name-commonLabels
[field-name-commonAnnotations]: plugins/builtins.md#field-name-commonAnnotations
[field-name-configMapGenerator]: plugins/builtins.md#field-name-configMapGenerator
An explanation of the fields in a [kustomization.yaml](glossary.md#kustomization) file.
@@ -52,7 +38,6 @@ What transformations (customizations) should be applied?
| [namePrefix](#nameprefix) | string | Prepends value to the names of all resources |
| [nameSuffix](#namesuffix) | string | The value is appended to the names of all resources. |
| [replicas](#replicas) | list | Replicas modifies the number of replicas of a resource. |
| [patches](#patches) | list | Each entry should resolve to a patch that can be applied to multiple targets. |
|[patchesStrategicMerge](#patchesstrategicmerge)| list |Each entry in this list should resolve to a partial or complete resource definition file.|
|[patchesJson6902](#patchesjson6902)| list |Each entry in this list should resolve to a kubernetes object and a JSON patch that will be applied to the object.|
|[transformers](#transformers)|list|[plugin](plugins) configuration files|
@@ -79,7 +64,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1
### bases
_The `bases` field was deprecated in v2.1.0._
The `bases` field was deprecated in v2.1.0.
Move entries into the [resources](#resources)
field. This allows bases - which are still a
@@ -87,13 +72,51 @@ field. This allows bases - which are still a
ordered relative to other input resources.
### commonLabels
See [field-name-commonLabels].
Adds labels to all resources and selectors
```
commonLabels:
someName: someValue
owner: alice
app: bingo
```
### commonAnnotations
See [field-name-commonAnnotations].
Adds annotions (non-identifying metadata) to add
all resources. Like labels, these are key value
pairs.
```
commonAnnotations:
oncallPager: 800-555-1212
```
### configMapGenerator
See [field-name-configMapGenerator].
Each entry in this list results in the creation of
one ConfigMap resource (it's a generator of n maps).
The example below creates two ConfigMaps. One with the
names and contents of the given files, the other with
key/value as data.
Each configMapGenerator item accepts a parameter of
`behavior: [create|replace|merge]`.
This allows an overlay to modify or
replace an existing configMap from the parent.
```
configMapGenerator:
- name: myJavaServerProps
files:
- application.properties
- more.properties
- name: myJavaServerEnvVars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
```
### crds
@@ -120,7 +143,9 @@ The annotations can be put into openAPI definitions are:
- "x-kubernetes-object-ref-kind": "Secret",
- "x-kubernetes-object-ref-name-key": "name",
```
crds:
- crds/typeA.yaml
- crds/typeB.yaml
@@ -158,7 +183,42 @@ generators:
### images
See [field-name-images].
Images modify the name, tags and/or digest for images without creating patches.
E.g. Given this kubernetes Deployment fragment:
```
containers:
- name: mypostgresdb
image: postgres:8
- name: nginxapp
image: nginx:1.7.9
- name: myapp
image: my-demo-app:latest
- name: alpine-app
image: alpine:3.7
```
one can change the `image` in the following ways:
- `postgres:8` to `my-registry/my-postgres:v1`,
- nginx tag `1.7.9` to `1.8.0`,
- image name `my-demo-app` to `my-app`,
- alpine's tag `3.7` to a digest value
all with the following *kustomization*:
```
images:
- name: postgres
newName: my-registry/my-postgres
newTag: v1
- name: nginx
newTag: 1.8.0
- name: my-demo-app
newName: my-app
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
```
### inventory
@@ -172,33 +232,143 @@ If missing, this field's value defaults to
kind: Kustomization
```
### namespace
See [field-name-namespace].
Adds namespace to all resources
```
namespace: my-namespace
```
### namePrefix
See [field-name-namePrefix].
Prepends value to the names of all resources
Ex. a deployment named `wordpress` would become `alices-wordpress`
```
namePrefix: alices-
```
### nameSuffix
See [field-name-nameSuffix].
The value is appended to the names of all
resources. Ex. A deployment named `wordpress`
would become `wordpress-v2`.
### patches
The suffix is appended before content has if
resource type is ConfigMap or Secret.
See [field-name-patches].
```
nameSuffix: -v2
```
### patchesStrategicMerge
See [field-name-patchesStrategicMerge].
Each entry in this list should be a relative path
resolving to a partial or complete resource
definition file.
The names in these (possibly partial) resource
files must match names already loaded via the
`resources` field. These entries are used to
_patch_ (modify) the known resources.
Small patches that do one thing are best, e.g. modify
a memory request/limit, change an env var in a
ConfigMap, etc. Small patches are easy to review and
easy to mix together in overlays.
```
patchesStrategicMerge:
- service_port_8888.yaml
- deployment_increase_replicas.yaml
- deployment_increase_memory.yaml
```
### patchesJson6902
See [field-name-patchesJson6902].
Each entry in this list should resolve to
a kubernetes object and a JSON patch that will be applied
to the object.
The JSON patch is documented at https://tools.ietf.org/html/rfc6902
target field points to a kubernetes object within the same kustomization
by the object's group, version, kind, name and namespace.
path field is a relative file path of a JSON patch file.
The content in this patch file can be either in JSON format as
```
[
{"op": "add", "path": "/some/new/path", "value": "value"},
{"op": "replace", "path": "/some/existing/path", "value": "new value"}
]
```
or in YAML format as
```
- op: add
path: /some/new/path
value: value
- op: replace
path: /some/existing/path
value: new value
```
```
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
path: add_init_container.yaml
- target:
version: v1
kind: Service
name: my-service
path: add_service_annotation.yaml
```
### replicas
See [field-name-replicas].
Replicas modified the number of replicas for a resource.
E.g. Given this kubernetes Deployment fragment:
```
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 3
```
one can change the number of replicas to 5
by adding the following to your kustomization:
```
replicas:
- name: deployment-name
count: 5
```
This field accepts a list, so many resources can
be modified at the same time.
#### Limitation
As this declaration does not take in a `kind:` nor a `group:`
it will match any `group` and `kind` that has a matching name and
that is one of:
- `Deployment`
- `ReplicationController`
- `ReplicaSet`
- `StatefulSet`
For more complex use cases, revert to using a patch.
### resources
@@ -236,7 +406,28 @@ must contain a `kustomization.yaml` file.
### secretGenerator
See [field-name-secretGenerator].
Each entry in this list results in the creation of
one Secret resource (it's a generator of n secrets).
```
secretGenerator:
- name: app-tls
files:
- secret/tls.cert
- secret/tls.key
type: "kubernetes.io/tls"
- name: app-tls-namespaced
# you can define a namespace to generate secret in, defaults to: "default"
namespace: apps
files:
- tls.crt=catsecret/tls.cert
- tls.key=secret/tls.key
type: "kubernetes.io/tls"
- name: env_file_secret
envs:
- env.txt
type: Opaque
```
### vars

View File

@@ -36,7 +36,6 @@
[rpm]: https://en.wikipedia.org/wiki/Rpm_(software)
[strategic-merge]: https://git.k8s.io/community/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[target]: #target
[transformer]: #transformer
[variant]: #variant
[variants]: #variant
[workflow]: workflows.md
@@ -377,8 +376,9 @@ value is a list.
To change this
default behavior, add a _directive_. Recognized
directives in YAML patches are _replace_ (the default)
and _delete_ (see [these notes][strategic-merge]).
directives include _replace_ (the default), _merge_
(avoid replacing a list), _delete_ and a few more
(see [these notes][strategic-merge]).
Note that for custom resources, SMPs are treated as
[json merge patches][JSONMergePatch].

View File

@@ -223,7 +223,6 @@ provided in the kustomization file).
[helm chart inflator]: ../../plugin/someteam.example.com/v1/chartinflator
[bashed config map]: ../../plugin/someteam.example.com/v1/bashedconfigmap
[sed transformer]: ../../plugin/someteam.example.com/v1/sedtransformer
[hashicorp go-getter]: ../../plugin/someteam.example.com/v1/gogetter
#### Examples
@@ -231,7 +230,7 @@ provided in the kustomization file).
* [bashed config map] - Super simple configMap generation from bash.
* [sed transformer] - Define your unstructured edits using a
plugin like this one.
* [hashicorp go-getter] - Download kustomize layes and build it to generate resources
A generator plugin accepts nothing on `stdin`, but emits
generated resources to `stdout`.
@@ -244,46 +243,6 @@ kustomize uses an exec plugin adapter to provide
marshalled resources on `stdin` and capture
`stdout` for further processing.
#### Generator Options
A generator exec plugin can adjust the generator options for the resources it emits by setting one of the following internal annotations.
> NOTE: These annotations are local to kustomize and will not be included in the final output.
**`kustomize.config.k8s.io/needs-hash`**
Resources can be marked as needing to be processed by the internal hash transformer by including the `needs-hash` annotation. When set valid values for the annotation are `"true"` and `"false"` which respectively enable or disable hash suffixing for the resource. Omitting the annotation is equivalent to setting the value `"false"`.
If this annotation is set on a resource not supported by the hash transformer the build will fail.
Example:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-test
annotations:
kustomize.config.k8s.io/needs-hash: "true"
data:
foo: bar
```
**`kustomize.config.k8s.io/behavior`**
The `behavior` annotation will influence how conflicts are handled for resources emitted by the plugin. Valid values include "create", "merge", and "replace" with "create" being the default.
Example:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-test
annotations:
kustomize.config.k8s.io/behavior: "merge"
data:
foo: bar
```
### Go plugins
Be sure to read [Go plugin caveats](goPluginCaveats.md).
@@ -305,8 +264,8 @@ A Go plugin for kustomize looks like this:
> package main
>
> import (
> "sigs.k8s.io/kustomize/api/ifc"
> "sigs.k8s.io/kustomize/api/resmap"
> "sigs.k8s.io/kustomize/v3/pkg/ifc"
> "sigs.k8s.io/kustomize/v3/pkg/resmap"
> ...
> )
>

View File

@@ -1,683 +0,0 @@
<!--
TODO: Generate this file (or files) from
data in directories under plugin/builtin.
This file too hard to maintain distinctly
from what's going on in those directories.
We could expand pluginator to do this, since
it already scans the relevant files in the
relevant directory to generate the static
factory methods for plugins.
-->
# Builtin Plugins
A list of kustomize's builtin plugins (both
generators and transformers).
For each plugin, an example is given for
* implicitly triggering
the plugin via a dedicated kustomization
file field (e.g. the `AnnotationsTransformer` is
triggered by the `commonAnnotations` field).
* explicitly triggering the plugin
via the `generators` or `transformers` field
(by providing a config file specifying the
plugin).
The former method is convenient but limited in
power as most of the plugins arguments must
be defaulted. The latter method allows for
complete plugin argument specification.
[types.GeneratorOptions]: ../../api/types/generatoroptions.go
[types.SecretArgs]: ../../api/types/secretargs.go
[types.ConfigMapArgs]: ../../api/types/configmapargs.go
[config.FieldSpec]: ../../api/plugins/builtinconfig/fieldspec.go
[types.ObjectMeta]: ../../api/types/objectmeta.go
[types.Selector]: ../../api/types/selector.go
[types.Replica]: ../../api/types/replica.go
[types.PatchStrategicMerge]: ../../api/types/patchstrategicmerge.go
[types.PatchTarget]: ../../api/types/patchtarget.go
[image.Image]: ../../api/types/image.go
## _AnnotationTransformer_
### Usage via `kustomization.yaml`
#### field name: `commonAnnotations`
Adds annotions (non-identifying metadata) to add
all resources. Like labels, these are key value
pairs.
```
commonAnnotations:
oncallPager: 800-555-1212
```
### Usage via plugin
#### Arguments
> Annotations map\[string\]string
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: AnnotationsTransformer
> metadata:
> name: not-important-to-example
> annotations:
> app: myApp
> greeting/morning: a string with blanks
> fieldSpecs:
> - path: metadata/annotations
> create: true
> ```
## _ConfigMapGenerator_
### Usage via `kustomization.yaml`
#### field name: `configMapGenerator`
Each entry in this list results in the creation of
one ConfigMap resource (it's a generator of n maps).
The example below creates two ConfigMaps. One with the
names and contents of the given files, the other with
key/value as data.
Each configMapGenerator item accepts a parameter of
`behavior: [create|replace|merge]`.
This allows an overlay to modify or
replace an existing configMap from the parent.
```
configMapGenerator:
- name: my-java-server-props
files:
- application.properties
- more.properties
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
```
It is also possible to
[define a key](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-the-key-to-use-when-creating-a-configmap-from-a-file)
to set a name different than the filename.
The example below creates a ConfigMap
with the name of file as `myFileName.ini`
while the _actual_ filename from which the
configmap is created is `whatever.ini`.
```
configMapGenerator:
- name: app-whatever
files:
- myFileName.ini=whatever.ini
```
### Usage via plugin
#### Arguments
> [types.GeneratorOptions]
>
> [types.ConfigMapArgs]
#### Example
> ```
> apiVersion: builtin
> kind: ConfigMapGenerator
> metadata:
> name: mymap
> envs:
> - devops.env
> - uxteam.env
> literals:
> - FRUIT=apple
> - VEGETABLE=carrot
> ```
## _ImageTagTransformer_
### Usage via `kustomization.yaml`
#### field name: `image`
Images modify the name, tags and/or digest for images
without creating patches. E.g. Given this
kubernetes Deployment fragment:
```
containers:
- name: mypostgresdb
image: postgres:8
- name: nginxapp
image: nginx:1.7.9
- name: myapp
image: my-demo-app:latest
- name: alpine-app
image: alpine:3.7
```
one can change the `image` in the following ways:
- `postgres:8` to `my-registry/my-postgres:v1`,
- nginx tag `1.7.9` to `1.8.0`,
- image name `my-demo-app` to `my-app`,
- alpine's tag `3.7` to a digest value
all with the following *kustomization*:
```
images:
- name: postgres
newName: my-registry/my-postgres
newTag: v1
- name: nginx
newTag: 1.8.0
- name: my-demo-app
newName: my-app
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
```
### Usage via plugin
#### Arguments
> ImageTag [image.Image]
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: ImageTagTransformer
> metadata:
> name: not-important-to-example
> imageTag:
> name: nginx
> newTag: v2
> ```
## _LabelTransformer_
### Usage via `kustomization.yaml`
#### field name: `commonLabels`
Adds labels to all resources and selectors
```
commonLabels:
someName: someValue
owner: alice
app: bingo
```
### Usage via plugin
#### Arguments
> Labels map\[string\]string
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: LabelTransformer
> metadata:
> name: not-important-to-example
> labels:
> app: myApp
> env: production
> fieldSpecs:
> - path: metadata/labels
> create: true
> ```
## _NamespaceTransformer_
### Usage via `kustomization.yaml`
#### field name: `namespace`
Adds namespace to all resources
```
namespace: my-namespace
```
### Usage via plugin
#### Arguments
> [types.ObjectMeta]
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: NamespaceTransformer
> metadata:
> name: not-important-to-example
> namespace: test
> fieldSpecs:
> - path: metadata/namespace
> create: true
> - path: subjects
> kind: RoleBinding
> group: rbac.authorization.k8s.io
> - path: subjects
> kind: ClusterRoleBinding
> group: rbac.authorization.k8s.io
> ```
## _PatchesJson6902_
### Usage via `kustomization.yaml`
#### field name: `patchesJson6902`
Each entry in this list should resolve to
a kubernetes object and a JSON patch that will be applied
to the object.
The JSON patch is documented at https://tools.ietf.org/html/rfc6902
target field points to a kubernetes object within the same kustomization
by the object's group, version, kind, name and namespace.
path field is a relative file path of a JSON patch file.
The content in this patch file can be either in JSON format as
```
[
{"op": "add", "path": "/some/new/path", "value": "value"},
{"op": "replace", "path": "/some/existing/path", "value": "new value"}
]
```
or in YAML format as
```
- op: add
path: /some/new/path
value: value
- op: replace
path: /some/existing/path
value: new value
```
```
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
path: add_init_container.yaml
- target:
version: v1
kind: Service
name: my-service
path: add_service_annotation.yaml
```
The patch content can be an inline string as well:
```
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
patch: |-
- op: add
path: /some/new/path
value: value
- op: replace
path: /some/existing/path
value: "new value"
```
### Usage via plugin
#### Arguments
> Target [types.PatchTarget]
>
> Path string
>
> JsonOp string
#### Example
> ```
> apiVersion: builtin
> kind: PatchJson6902Transformer
> metadata:
> name: not-important-to-example
> target:
> group: apps
> version: v1
> kind: Deployment
> name: my-deploy
> path: jsonpatch.json
> ```
## _PatchesStrategicMerge_
### Usage via `kustomization.yaml`
#### field name: `patchesStrategicMerge`
Each entry in this list should be either a relative
file path or an inline content
resolving to a partial or complete resource
definition.
The names in these (possibly partial) resource
files must match names already loaded via the
`resources` field. These entries are used to
_patch_ (modify) the known resources.
Small patches that do one thing are best, e.g. modify
a memory request/limit, change an env var in a
ConfigMap, etc. Small patches are easy to review and
easy to mix together in overlays.
```
patchesStrategicMerge:
- service_port_8888.yaml
- deployment_increase_replicas.yaml
- deployment_increase_memory.yaml
```
The patch content can be a inline string as well.
```
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nignx:latest
```
Note that kustomize does not support more than one patch
for the same object that contain a _delete_ directive. To remove
several fields / slice elements from an object create a single
patch that performs all the needed deletions.
### Usage via plugin
#### Arguments
> Paths \[\][types.PatchStrategicMerge]
>
> Patches string
#### Example
> ```
> apiVersion: builtin
> kind: PatchStrategicMergeTransformer
> metadata:
> name: not-important-to-example
> paths:
> - patch.yaml
> ```
## _PatchTransformer_
### Usage via `kustomization.yaml`
#### field name: `patches`
Each entry in this list should resolve to an Patch
object, which includes a patch and a target selector.
The patch can be either a strategic merge patch or a
JSON patch. it can be either a patch file or an inline
string. The target selects
resources by group, version, kind, name, namespace,
labelSelector and annotationSelector. A resource
which matches all the specified fields is selected
to apply the patch.
```
patches:
- path: patch.yaml
target:
group: apps
version: v1
kind: Deployment
name: deploy.*
labelSelector: "env=dev"
annotationSelector: "zone=west"
- patch: |-
- op: replace
path: /some/existing/path
value: new value
target:
kind: MyKind
labelSelector: "env=dev"
```
The `name` and `namespace` fields of the patch target selector are
automatically anchored regular expressions. This means that the value `myapp`
is equivalent to `^myapp$`.
### Usage via plugin
#### Arguments
> Path string
>
> Patch string
>
> Target \*[types.Selector]
#### Example
> ```
> apiVersion: builtin
> kind: PatchTransformer
> metadata:
> name: not-important-to-example
> patch: '[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "nginx:latest"}]'
> target:
> name: .*Deploy
> kind: Deployment
> ```
## _PrefixSuffixTransformer_
### Usage via `kustomization.yaml`
#### field names: `namePrefix`, `nameSuffix`
Prepends or postfixes the value to the names
of all resources.
E.g. a deployment named `wordpress` could
become `alices-wordpress` or `wordpress-v2`
or `alices-wordpress-v2`.
```
namePrefix: alices-
nameSuffix: -v2
```
The suffix is appended before the content hash if
the resource type is ConfigMap or Secret.
### Usage via plugin
#### Arguments
> Prefix string
>
> Suffix string
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: PrefixSuffixTransformer
> metadata:
> name: not-important-to-example
> prefix: baked-
> suffix: -pie
> fieldSpecs:
> - path: metadata/name
> ```
## _ReplicaCountTransformer_
### Usage via `kustomization.yaml`
#### field name: `replicas`
Replicas modified the number of replicas for a resource.
E.g. Given this kubernetes Deployment fragment:
```
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 3
```
one can change the number of replicas to 5
by adding the following to your kustomization:
```
replicas:
- name: deployment-name
count: 5
```
This field accepts a list, so many resources can
be modified at the same time.
As this declaration does not take in a `kind:` nor a `group:`
it will match any `group` and `kind` that has a matching name and
that is one of:
- `Deployment`
- `ReplicationController`
- `ReplicaSet`
- `StatefulSet`
For more complex use cases, revert to using a patch.
### Usage via plugin
#### Arguments
> Replica [types.Replica]
>
> FieldSpecs \[\][config.FieldSpec]
#### Example
> ```
> apiVersion: builtin
> kind: ReplicaCountTransformer
> metadata:
> name: not-important-to-example
> replica:
> name: myapp
> count: 23
> fieldSpecs:
> - path: spec/replicas
> create: true
> kind: Deployment
> - path: spec/replicas
> create: true
> kind: ReplicationController
> ```
## _SecretGenerator_
### Usage via `kustomization.yaml`
#### field name: `secretGenerator`
Each entry in the argument list
results in the creation of
one Secret resource
(it's a generator of n secrets).
```
secretGenerator:
- name: app-tls
files:
- secret/tls.cert
- secret/tls.key
type: "kubernetes.io/tls"
- name: app-tls-namespaced
# you can define a namespace to generate
# a secret in, defaults to: "default"
namespace: apps
files:
- tls.crt=catsecret/tls.cert
- tls.key=secret/tls.key
type: "kubernetes.io/tls"
- name: env_file_secret
envs:
- env.txt
type: Opaque
```
### Usage via plugin
#### Arguments
> [types.ObjectMeta]
>
> [types.GeneratorOptions]
>
> [types.SecretArgs]
#### Example
> ```
> apiVersion: builtin
> kind: SecretGenerator
> metadata:
> name: my-secret
> namespace: whatever
> behavior: merge
> envs:
> - a.env
> - b.env
> files:
> - obscure=longsecret.txt
> literals:
> - FRUIT=apple
> - VEGETABLE=carrot
> ```

View File

@@ -12,7 +12,7 @@ current setup.
#### requirements
* linux, git, curl, Go 1.13
* linux, git, curl, Go 1.12
## Make a place to work
@@ -201,7 +201,7 @@ chmod a+x $MY_PLUGIN_DIR/SillyConfigMapGenerator
```
mkdir -p $DEMO/bin
gh=https://github.com/kubernetes-sigs/kustomize/releases/download
url=$gh/v3.0.0/kustomize_3.0.0_linux_amd64
url=$gh/v3.0.0-pre/kustomize_3.0.0-pre_linux_amd64
curl -o $DEMO/bin/kustomize -L $url
chmod u+x $DEMO/bin/kustomize
```
@@ -226,3 +226,4 @@ Above, if you had set
there would be no need to use `XDG_CONFIG_HOME` in the
_kustomize_ command above.

View File

@@ -52,8 +52,8 @@ kustomize and the plugin_.
This means a one-time run of
```
# Or whatever is appropriate at time of reading
GOPATH=${whatever} GO111MODULE=on go get sigs.k8s.io/kustomize/api
GOPATH=${whatever} go get \
sigs.k8s.io/kustomize/cmd/kustomize@${releaseVersion}
```
and then a normal development cycle using

View File

@@ -1,14 +1,10 @@
# Go Plugin Guided Example for Linux
This is a (no reading allowed!) 60 second copy/paste guided
example. Full plugin docs [here](README.md).
[SopsEncodedSecrets repository]: https://github.com/monopole/sopsencodedsecrets
[Go plugin]: https://golang.org/pkg/plugin
[Go plugin caveats]: goPluginCaveats.md
This is a (no reading allowed!) 60 second copy/paste guided
example.
Full plugin docs [here](README.md).
Be sure to read the [Go plugin caveats].
This demo uses a Go plugin, `SopsEncodedSecrets`,
that lives in the [sopsencodedsecrets repository].
@@ -21,32 +17,23 @@ current setup.
#### requirements
* linux, git, curl, Go 1.13
For encryption
* gpg
Or
* Google cloud (gcloud) install
* a Google account with KMS permission
* linux, git, curl, Go 1.12
* Google cloud (gcloud) install
* a Google account (will use Google kms -
volunteers needed to convert to a GPG example).
## Make a place to work
```shell
# Keeping these separate to avoid cluttering the DEMO dir.
```
DEMO=$(mktemp -d)
tmpGoPath=$(mktemp -d)
```
## Install kustomize
Need v3.0.0 for what follows, and you must _compile_
it (not download the binary from the release page):
Need v3.0.0 for what follows:
```shell
GOPATH=$tmpGoPath go install sigs.k8s.io/kustomize/kustomize
```
GOBIN=$DEMO/bin go get sigs.k8s.io/kustomize/v3/cmd/kustomize@v3.0.0-pre
```
## Make a home for plugins
@@ -67,8 +54,8 @@ The kustomize program reads the config file
kustomization file), then locates the Go plugin's
object code at the following location:
> ```shell
> $XDG_CONFIG_HOME/kustomize/plugin/$apiVersion/$lKind/$kind.so
> ```
> $XGD_CONFIG_HOME/kustomize/plugin/$apiVersion/$lKind/$kind.so
> ```
where `lKind` holds the lowercased kind. The
@@ -87,11 +74,11 @@ left to plugins to find their own config.
This demo will house the plugin it uses at the
ephemeral directory
```shell
```
PLUGIN_ROOT=$DEMO/kustomize/plugin
```
and ephemerally set `XDG_CONFIG_HOME` on a command
and ephemerally set `XGD_CONFIG_HOME` on a command
line below.
### What apiVersion and kind?
@@ -110,10 +97,10 @@ to a plugin.
This demo uses a plugin called _SopsEncodedSecrets_,
and it lives in the [SopsEncodedSecrets repository].
Somewhat arbitrarily, we'll chose to install
Somewhat arbitrarily, we'll chose to install
this plugin with
```shell
```
apiVersion=mygenerators
kind=SopsEncodedSecrets
```
@@ -124,7 +111,7 @@ By convention, the ultimate home of the plugin
code and supplemental data, tests, documentation,
etc. is the lowercase form of its kind.
```shell
```
lKind=$(echo $kind | awk '{print tolower($0)}')
```
@@ -134,7 +121,7 @@ In this case, the repo name matches the lowercase
kind already, so we just clone the repo and get
the proper directory name automatically:
```shell
```
mkdir -p $PLUGIN_ROOT/${apiVersion}
cd $PLUGIN_ROOT/${apiVersion}
git clone git@github.com:monopole/sopsencodedsecrets.git
@@ -142,7 +129,7 @@ git clone git@github.com:monopole/sopsencodedsecrets.git
Remember this directory:
```shell
```
MY_PLUGIN_DIR=$PLUGIN_ROOT/${apiVersion}/${lKind}
```
@@ -151,16 +138,16 @@ MY_PLUGIN_DIR=$PLUGIN_ROOT/${apiVersion}/${lKind}
Plugins may come with their own tests.
This one does, and it hopefully passes:
```shell
```
cd $MY_PLUGIN_DIR
go test SopsEncodedSecrets_test.go
```
Build the object code for use by kustomize:
```shell
```
cd $MY_PLUGIN_DIR
GOPATH=$tmpGoPath go build -buildmode plugin -o ${kind}.so ${kind}.go
go build -buildmode plugin -o ${kind}.so ${kind}.go
```
This step may succeed, but kustomize might
@@ -173,10 +160,10 @@ dependency [skew].
On load failure
* be sure to build the plugin with the same
version of Go (_go1.13_) on the same `$GOOS`
version of Go (_go1.12_) on the same `$GOOS`
(_linux_) and `$GOARCH` (_amd64_) used to build
the kustomize being [used in this demo].
* change the plugin's dependencies in its `go.mod`
to match the versions used by kustomize (check
kustomize's `go.mod` used in its tagged commit).
@@ -193,11 +180,11 @@ reusable instead of bizarrely woven throughout the
code as a individual special cases.
## Create a kustomization
Make a kustomization directory to
hold all your config:
```shell
```
MYAPP=$DEMO/myapp
mkdir -p $MYAPP
```
@@ -207,13 +194,12 @@ Make a config file for the SopsEncodedSecrets plugin.
Its `apiVersion` and `kind` allow the plugin to be
found:
```shell
```
cat <<EOF >$MYAPP/secGenerator.yaml
apiVersion: ${apiVersion}
kind: ${kind}
metadata:
name: mySecretGenerator
name: forbiddenValues
name: forbiddenValues
namespace: production
file: myEncryptedData.yaml
keys:
@@ -228,7 +214,7 @@ This plugin expects to find more data in
Make a kustomization file referencing the plugin
config:
```shell
```
cat <<EOF >$MYAPP/kustomization.yaml
commonLabels:
app: hello
@@ -237,46 +223,31 @@ generators:
EOF
```
Now generate the real encrypted data.
Now for the hard part. Generate the real encrypted data.
### Assure you have an encryption tool installed
We're going to use [sops](https://github.com/mozilla/sops) to encode a file. Choose either GPG or Google Cloud KMS as the secret provider to continue.
### Assure you have a Google Cloud sops key ring.
#### GPG
We're going to use [sops](https://github.com/mozilla/sops) to encode a file.
Try this:
```shell
gpg --list-keys
```
If it returns a list, presumably you've already created keys. If not, try import test keys from sops for dev.
```shell
curl https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc | gpg --import
SOPS_PGP_FP="1022470DE3F0BC54BC6AB62DE05550BC07FB1A0A"
```
#### Google Cloude KMS
Try this:
```shell
gcloud kms keys list --location global --keyring sops
```
If it succeeds, presumably you've already created keys and placed them in a keyring called sops. If not, do this:
If it succeeds, presumably you've already
created keys and placed them in a keyring called `sops`.
If not, do this:
```shell
```
gcloud kms keyrings create sops --location global
gcloud kms keys create sops-key --location global \
--keyring sops --purpose encryption
```
Extract your keyLocation for use below:
```shell
```
keyLocation=$(\
gcloud kms keys list --location global --keyring sops |\
grep GOOGLE | cut -d " " -f1)
@@ -285,73 +256,42 @@ echo $keyLocation
### Install `sops`
```shell
GOPATH=$tmpGoPath go install go.mozilla.org/sops/cmd/sops
```
GOBIN=$DEMO/bin go install go.mozilla.org/sops/cmd/sops
```
### Create data encrypted with your private key
### Create data encrypted with your Google Cloud key
Create raw data to encrypt:
```shell
```
cat <<EOF >$MYAPP/myClearData.yaml
VEGETABLE: carrot
ROCKET: saturn-v
FRUIT: apple
CAR: dymaxion
EOF
```
Encrypt the data into file the plugin wants to read:
With PGP
```shell
$tmpGoPath/bin/sops --encrypt \
--pgp $SOPS_PGP_FP \
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
```
Or GCP KMS
```shell
$tmpGoPath/bin/sops --encrypt \
$DEMO/bin/sops --encrypt \
--gcp-kms $keyLocation \
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
```
Review the files
```shell
Review the files
```
tree $DEMO
```
This should look something like:
> ```shell
> /tmp/tmp.0kIE9VclPt
> ├── kustomize
> │   └── plugin
> │   └── mygenerators
> │   └── sopsencodedsecrets
> │   ├── go.mod
> │   ├── go.sum
> │   ├── LICENSE
> │   ├── README.md
> │   ├── SopsEncodedSecrets.go
> │   ├── SopsEncodedSecrets.so
> │   └── SopsEncodedSecrets_test.go
> └── myapp
> ├── kustomization.yaml
> ├── myClearData.yaml
> ├── myEncryptedData.yaml
> └── secGenerator.yaml
> ```
## Build your app, using the plugin:
```shell
XDG_CONFIG_HOME=$DEMO $tmpGoPath/bin/kustomize build --enable_alpha_plugins $MYAPP
```
XDG_CONFIG_HOME=$DEMO $DEMO/bin/kustomize build --enable_alpha_plugins $MYAPP
```
This should emit a kubernetes secret, with
@@ -359,9 +299,10 @@ encrypted data for the names `ROCKET` and `CAR`.
Above, if you had set
> ```shell
> ```
> PLUGIN_ROOT=$HOME/.config/kustomize/plugin
> ```
there would be no need to use `XDG_CONFIG_HOME` in the
_kustomize_ command above.

View File

@@ -223,7 +223,7 @@ normal k8s resources means that one can generate
or transform a generator or a transformer (see
[TestTransformerTransformers]).
[TestTransformerTransformers]: ../api/target/transformerplugin_test.go
[TestTransformerTransformers]: ../pkg/target/transformerplugin_test.go
### `replicas` field

View File

@@ -1,15 +1,18 @@
# kustomize 3.0.0
This release is basically [v2.1.0](v2.1.0.md),
with many post-v2.1.0 bugs fixed (in about 150
commits) and a `v3` in Go package paths.
with some post-v2.1.0 bugs fixed and a `v3` in Go
package paths.
[plugin]: https://github.com/kubernetes-sigs/kustomize/tree/master/docs/plugins
The major version increment to `v3` puts a new
floor on a stable API for [plugin] developers
(both _Go_ plugin developers and _exec_ plugin
developers who happen to use Go).
developers who happen to use Go), to carry them
through the coming series of minor releases and
patches.
### Why so soon after v2.1.0?

View File

@@ -1,127 +0,0 @@
# kustomize 3.1.0
## Extended patches
Since this version, Kustomize allows applying one patch to multiple resources. This works for both Strategic Merge Patch and JSON Patch. Take a look at [patch multiple objects](../examples/patchMultipleObjects.md).
## Improved Resource Matching
Multiple improvements have been made to allow the user to leverage "namespace"
instead/or with "name suffix/prefix" to segregate resources.
### Patch resolution improvement
The following example demonstrates how using the namespace field in the patch definition,
will let the user define two different patches against two different Deployment having the
same "deploy1" name but in different namespaces in the same Kustomize context/folder.
Unless the `namespace:` field has been specified in the kustomization.yaml, no namespace
value will be handled as Kubernetes `default` namespace.
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
namespace: main
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ANOTHERENV
value: TESTVALUE
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
namespace: production
spec:
template:
spec:
containers:
- name: main
env:
- name: ANOTHERENV
value: PRODVALUE
```
### Variable resolution improvement
It is possible to add namespace field to the variable declaration. In the following example,
two `Service` objects with the same `elasticsearch` name have been declared.
Specifying the namespace in the objRef of the corresponding varriables, allows Kustomize to
resovlve thoses variables.
If the namespace is not specified, Kustomize will handle it has a "wildcard" value.
Extract of kustomization.yaml:
```yaml
vars:
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
namespace: test
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
namespace: dev
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
```
### Simultaneous change of names and namespaces
Kustomize is now able to deal with simultaneous changes of name and namespace.
Special attention has been paid the handling of:
- ClusterRoleBinding/RoleBinding "subjects" field,
- ValidatingWebhookConfiguration "webhooks" field.
The user should be able to use a kustomization.yaml as shown in the example bellow
even if ClusterRoleBind,RoleBinding and ValidatingWebookConfiguration are part of the
resources he needs to declare.
Extract of kustomization.yaml:
```yaml
namePrefix: pfx-
nameSuffix: -sfx
namespace: testnamespace
resources:
...
```
### Resource and Kustomize Context matching.
Kustomize is now able to support more aggregation patterns.
If for instance, the top level of kustomization.yaml, is simply
combining sub-components, (as in the following example), Kustomize has improved
resource matching capabilities. This removes some of the constraints which were
present on the utilization of prefix/suffix and namespace transformers in the
individual components.
```yaml
resources:
- ../component1
- ../component2
- ../component3
```
## Other improvements
- Image transformation has been improved. This allows the user to update the sha256 of
an image with another sha256.
- Multiple default transformer configuration entries have been added, removing the need for the
user to add them as part of the `configurations:` section of the kustomization.yaml.
- `kustomize` help command has been tidied up.

View File

@@ -1,29 +0,0 @@
# kustomize 3.2.0
## Inline Patch
Since this version, Kustomize allows inline patches in all three of `patchesStrategicMerge`, `patchesJson6902` and `patches`. Take a look at [inline patch](../examples/inlinePatch.md).
## New Subcommand
Since this version, one can create a kustomization.yaml file in a directory through a `create` subcommand.
Create a new overlay from the base ../base
```
kustomize create --resources ../base
```
Create a new kustomization detecing resources in the current directory
```
kustomize create --autodetect
```
Once can also add all resources in the current directory recursively by
```
kustomize create --autodetect --recursive
```
### New Example Generator
A new example generator of using go-getter to download resources is added. Take a look at [go-getter generator](../examples/goGetterGeneratorPlugin.md).

View File

@@ -1,13 +0,0 @@
# kustomize 3.2.1
This is a patch release, with no new features from 3.2.0.
It reflects a change in dependence.
The kustomize binary is now built as a client, with no special
consideration, of the set of public packages represented by the Go
module at [https://github.com/kubernetes-sigs/kustomize].
kustomize the binary is now a client of the kustomize API
represented by the public package surface presented by
`https://github.com/kubernetes-sigs/kustomize/v{whatever}`

View File

@@ -1,114 +0,0 @@
# kustomize 3.3.0
[versioning policy documentation]: https://github.com/kubernetes-sigs/kustomize/blob/master/docs/versioningPolicy.md
[release process documentation]: https://github.com/kubernetes-sigs/kustomize/tree/master/releasing
## Summary of changes
### First release of the Go API-only module.
Many of the PRs since the last kustomize release were
around restructuring the _sigs.k8s.io/kustomize_
repository into three Go modules instead of just one.
The reasons for this are detailed in the [versioning
policy documentation], and what it means for releasing
is explained in the [release process documentation].
The tl;dr is that the top level module
`sigs.k8s.io/kustomize` now defines the kustomize Go
API, and the _kustomize_ CLI sits below it in an
independent module `sigs.k8s.io/kustomize/kustomize`.
The modules release independently, though in practice a
new release of the kustomize Go API will likely be
followed quickly by a new release of the `kustomize`
executable.
This is a necessary step to creating a much smaller
kustomize Go API surface that has some hope of
conforming to semantic versioning and being of some use
to clients.
The kustomize CLI will see the same kustomize Go API as
any other client.
The new semver-able API will begin with `v4.0.0` (not
yet released) and be a clean break with `v3` etc.
### Change log since v3.2.0
```
3c9d828f - Have kustomize CLI depend on kustomize Go API v3.3.0 (Jeffrey Regan)
5d800f0b - Merge pull request #1595 from monopole/threeReleases (Jeff Regan)
4eb2d5bc - Three builders. (Jeffrey Regan)
988af1ff - Update README.md (Jeff Regan)
1617183e - Merge pull request #1590 from monopole/releaseProcessUpdate (Kubernetes Prow Robot)
ee727464 - update release process doc (jregan)
c9e7dc3b - Merge pull request #1589 from monopole/moreTestsAroundKustFileName (Jeff Regan)
07e0e46a - improve tests for alternative kustomization file names (Jeffrey Regan)
404d2d63 - Merge pull request #1587 from monopole/reducePgmconfig (Jeff Regan)
baa0296a - Reduce size of pgmconfig package (Jeffrey Regan)
0f665ac1 - Merge pull request #1544 from ptux/add-transformer-href (Jeff Regan)
14b0a650 - Merge pull request #1581 from monopole/refactorFs (Jeff Regan)
2d58f8b8 - Break the dep between fs and pgmconfig. (Jeffrey Regan)
9a43ca53 - Merge pull request #1578 from nlamirault/fix/build-plugins-doc (Jeff Regan)
5372fc6f - Merge pull request #1579 from monopole/fsPackageCleanup (Jeff Regan)
86bc3440 - Merge pull request #1513 from nimohunter/fix_empty_list_item (Kubernetes Prow Robot)
a014f7d4 - Merge pull request #1561 from beautytiger/dev-190925 (Jeff Regan)
9a94bcb8 - Improve fs package and doc in prep to officially go public (Jeffrey Regan)
07634ef0 - Merge pull request #1575 from monopole/versioning (Jeff Regan)
995f88d6 - Update versioning notes. (jregan)
334a6467 - Fix: documentation link for plugins (Nicolas Lamirault)
08963ba5 - improve test code coverage in transformers (Guangming Wang)
326fb689 - Merge pull request #1570 from bzub/1234-go_plugin_doc (Jeff Regan)
970ce67c - Update goPluginCaveats.md (Jeff Regan)
98d18930 - Update INSTALL.md (Jeff Regan)
d89b448c - Fix git tag recovery in cloud build. (Jeff Regan)
17bf9d32 - Update releasing README. (Jeff Regan)
a99aff1d - Merge pull request #1571 from monopole/updateCloudBuildProcess (Kubernetes Prow Robot)
a694ac7b - Update cloud build process for kustomize. (Jeffrey Regan)
b5b11ef6 - Fix compile kustomize example. (bzub)
fa1af6f5 - Merge pull request #1473 from richardmarshall/execpluginhash (Jeff Regan)
9288dec0 - Fix failing BashedConfigMapTest (Jeff Regan)
1a45dd0b - Merge pull request #1566 from monopole/releaseNotes3.2.1 (Kubernetes Prow Robot)
592c5acf - docs: Exec plugin generator options (Richard Marshall)
ac9424fa - tests: Add unit tests for update resource options (Richard Marshall)
79fbe7c4 - Support resource generator options in exec plugins (Richard Marshall)
f69d526f - v3.2.1 release notes (Jeff Regan)
07a95a60 - Merge pull request #1565 from monopole/tweakBinaryDepsBeforeTagging (Jeff Regan)
032b3857 - Pin the kustomize binary's dependence on kustomize libs. (jregan)
81062959 - Merge pull request #1564 from monopole/moveKustomizeBinaryToOwnModule (Kubernetes Prow Robot)
b82a8fd3 - Move the kustomize binary to its own module. (Jeffrey Regan)
2d0c22d6 - Merge pull request #1562 from keleustes/tools (Kubernetes Prow Robot)
aa342def - Pin tool versions using go modules (Ian Howell)
10786ec0 - Merge pull request #1554 from keleustes/readme (Kubernetes Prow Robot)
7c705687 - Update README.md to include Kubernetes 1.16 (Jerome Brette)
e8933d97 - Merge pull request #1560 from monopole/precommitTuneup (Jeff Regan)
9d7b6544 - Make pre-commit more portable and less tricky. (jregan)
7a0946a9 - Merge pull request #1558 from monopole/dependOnNewPluginatorModule (Jeff Regan)
def4f045 - Depend on new pluginator location. (Jeffrey Regan)
2f2408f1 - Merge pull request #1559 from monopole/compressCopyright (Jeff Regan)
3b9bcc48 - Compress copyright in the commands package. (Jeffrey Regan)
d0429ff4 - Merge pull request #1557 from monopole/pluginatorModule (Jeff Regan)
33deefc3 - Copy pluginator to its own module. (Jeffrey Regan)
9b3de82b - Merge pull request #1506 from Liujingfang1/release (Jeff Regan)
d217074f - Merge pull request #1550 from keleustes/apiversion (Kubernetes Prow Robot)
1d90ba7c - Fix typo in apiVersion yaml declaration (Jerome Brette)
eeeb4c36 - Merge pull request #1547 from keleustes/extensions (Kubernetes Prow Robot)
b1faa989 - Update Ingress apiVersion to networking.k8s.io/v1beta1 (Jerome Brette)
d8250c9e - move test case (nimohunter)
c9500466 - add transformer href (Wang(わん))
0c32691e - Merge pull request #1537 from jaypipes/gomod-install-note (Kubernetes Prow Robot)
88b1d627 - Merge pull request #1541 from rtnpro/patch-1 (Jeff Regan)
aec82066 - Update INSTALL.md (Jeff Regan)
20c2b53a - Merge pull request #1542 from monopole/tweakFilePathsInTest (Jeff Regan)
274b5c3b - Tweak file path handling and logging in test. (Jeffrey Regan)
b1fdaa23 - Fix typo in transformerconfigs README (Ratnadeep Debnath)
b5d5e70b - empty list or map item return error (nimohunter)
2e829853 - empty list or map item return error (nimohunter)
55941f57 - add note about GO111MODULE for source install (Jay Pipes)
9e226001 - empty list or map item return error (nimohunter)
77b63f96 - add release note for v3.2.0 (jingfangliu)
```

View File

@@ -1,140 +1,70 @@
# Versioning
Running `kustomize` means one is running a
particular version of a program (a CLI), using a
particular version of underlying packages (a Go
API), and reading a particular version of a
[kustomization] file.
particular version of a program, using a
particular version of underlying packages, and
reading a particular version of a [kustomization]
file.
> If you're having trouble with `go get`, please
> read [Go API Versioning](#go-api-versioning)
> and be patient.
## CLI Program Versioning
## Program Versioning
The command `kustomize version` prints a three
field version tag (e.g. `v3.0.0`) that aspires to
[semantic versioning].
This notion of semver applies only to the CLI;
the command names, their arguments and their flags.
When enough changes have accumulated to
warrant a new release, a [release process]
is followed, and the fields in the version
number are bumped per semver.
The major version changes when some backward
incompatibility appears in how the commands
behave.
## Kustomize packages
### Installation
At the time of writing, the kustomize program and
the packages it uses (and exports) are in the same
Go module (see the top level `go.mod` file in the
repo).
See the [installation docs](INSTALL.md).
[trailing major version indicator]: https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher
## Go API Versioning
Thus, they share the module's version number, per
its git tag (e.g. `v3.0.0`), whose major verion
number matches the [trailing major version
indicator] in the module name (e.g. the `/v3` in
`sigs.k8s.io/kustomize/v3`).
The public methods in the public packages
of module `sigs.k8s.io/kustomize/api` constitute
the _kustomize Go API_.
#### Version sigs.k8s.io/kustomize/v3 and earlier
[import path]: https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher
In `kustomize/v3` (and preceeding major versions), the
kustomize program and the API live the same Go
module at `sigs.k8s.io/kustomize`, at [import path]
`sigs.k8s.io/kustomize/v3`.
This has been fine for the CLI, but it presents a
problem for the Go API.
[minimal version selection]: https://research.swtch.com/vgo-mvs
The process around Go modules, in particular the
notion of [minimal version selection], demands
that the module respect semver.
Almost all the code in module
`sigs.k8s.io/kustomize/v3` is exposed (not in a
directory named `internal`). Even a minor
refactor changing a method name or argument type
in some deeply buried (but still public) method is
a backward incompatible change. As a result, Go
API semver hasn't been followed. This was a mistake.
Some options are
- continue to ignore Go API semver and stick to
CLI semver (eliminating the usefullness of
minimal version selection),
- obey semver, and increment the module's major
version number with every release (drastically
reducing the usefullness of minimal version
selection - since virtually all releases will
be major),
- slow down change in the huge API in favor of
stability, yet somehow continue to deliver
features,
- drastically reduce the API surface, stabilize on
semver there, and refactor as needed inside
`internal`.
The last option seems the most appealing.
#### The first stable API version is coming
The first stable API version will launch
as the Go module
```
sigs.k8s.io/kustomize/api
```
The _kustomize_ program itself (`main.go`
and CLI specific code) will have moved out of
`sigs.k8s.io/kustomize` and into the new module
`sigs.k8s.io/kustomize/kustomize`. This is a
submodule in the same repo, and it will retain its
current notion of semver (e.g. a backward
incompatible change in command behavior will
trigger a major version bump). This module will
not export packages; it's just home to a `main`
package.
The `sigs.k8s.io/kustomize/api` module will
obey semver with a sustainable public
surface, informed by current usage. Clients
should import packages from this module, i.e.
from import paths prefixed by
`sigs.k8s.io/kustomize/api/` at first,
and later by `sigs.k8s.io/kustomize/api/v2/`.
The kustomize binary
itself is an API client requiring this module.
The clients and API will evolve independently.
The non-internal packages in the Go module
`sigs.k8s.io/kustomize/v3`, introduced in
[v3.0.0](v3.0.0.md), conform to [semantic
versioning].
## Kustomization File Versioning
At the time of writing (circa release of v2.0.0):
The kustomization file is a struct that is part of
the kustomize Go API (the `sigs.k8s.io/kustomize`
module), but it also evolves as a k8s API object -
it has an `apiVersion` field containing its
own version number.
- A [kustomization] file is just a YAML file that
can be successfully parsed into a particular Go
struct defined in the `kustomize` binary.
- This struct does not have a version number,
which is the same as saying that its version
number matches the program's version number,
since it's compiled in.
### Field Change Policy
- A field's meaning cannot be changed.
- A field may be deprecated, then removed.
- Deprecation means triggering a _minor_ (semver)
version bump in the kustomize Go API, and
defining a migration path in a non-fatal error
message.
version bump in the program, and
defining a migration path in a non-fatal
error message.
- Removal means triggering a _major_ (semver)
version bump in the kustomize Go API, and fatal
error if field encountered (as with any unknown
field). Likewise a change in `apiVersion`.
version bump, and fatal error if field encountered
(as with any unknown field).
### The `edit fix` Command
@@ -144,12 +74,16 @@ fields, and writes it out again in the latest
format.
This is a type version upgrade mechanism that
works within _major_ API revisions. There is no
downgrade capability, as there's no use case for
it (see discussion below).
works within _major_ program revisions. There is
no downgrade capability, as there's no use case
for it (see discussion below).
### Examples
At the time of writing, in v1.0.x, there were 12
minor releases, with backward compatible
deprecations fixable via `edit fix`.
With the 2.0.0 release, there were three field
removals:
@@ -157,11 +91,13 @@ removals:
introduced, because the latter offers more
general features for image data manipulation.
`imageTag` was removed in v2.0.0.
- `patches` was deprecated and replaced by
`patchesStrategicMerge` when `patchesJson6902`
was introduced, to make a clearer
distinction between patch specification formats.
`patches` was removed in v2.0.0.
- `secretGenerator/commands` was removed
due to security concerns in v2.0.0
with no deprecation period.
@@ -181,8 +117,10 @@ native type signals:
- its reliability level (alpha vs beta vs
generally available),
- the existence of code to provide default values
to fields not present in a serialization,
- the existence of code to provide both forward
and backward conversion between different
versions of types.
@@ -204,13 +142,17 @@ For CRDs, there's a [proposal] on how to manage
versioning (e.g. a remote service can offer type
defaulting and conversions).
### Differences
### Kustomization file versioning
The critical difference between k8s API versioning
and kustomization file versioning is
- A k8s API server is able to go _forward_ and
_backward_ in versioning, to work with older
clients, over [some range].
- The `kustomize edit fix` command only moves
_forward_ within a _major_ API
_forward_ within a _major_ program
version.
At the time of writing, the YAML in a
@@ -229,26 +171,60 @@ the following rules.
Field names with dedicated meaning in k8s
(`metadata`, `spec`, `status`, etc.) aren't used.
This is enforced via code review.
#### Default values for k8s `kind` and `apiVersion`
#### Optional use of k8s `kind` and `apiVersion`
In `v3` or below, the two [special] k8s
resource fields [`kind`] and [`apiVersion`] may
be omitted from the kustomization file.
At the time of writing two [special] k8s
resource fields are allowed, but not required, in
a kustomization file: [`kind`] and [`apiVersion`].
If either field is present, they both must be.
If present, the value of `kind` must be:
If either field is present, they both must be, and
they must have the following values:
> ```
> kind: Kustomization
> ```
``` yaml
kind: Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1
```
If missing, the value of `apiVersion` defaults to
They are allowed to exist and have specific values
in a kustomization file only as a sort of
domain-squatting behavior for some future API. A
kustomize user gains nothing from adding these
fields to a kustomization file.
> ```
> apiVersion: kustomize.config.k8s.io/v1beta1
> ```
### Why not require `kind` and `apiVersion`
#### Ease of use and setting proper expectations
Use cases for a kustomization file don't include a
server storing muliple k8s kinds and offering
version downgrades.
The kustomization file is more akin to a
`Makefile`. A kustomize command can either read a
kustomization file, or it cannot, and in the later
case will complain as specifically as possible
about why (e.g. `unknown field Foo`).
So requiring a `kind` and `apiVersion` would just
be boilerplate in a user's files, and in all the
examples and tests.
Nevertheless, _a user still benefits from a
versioning policy_ and has a `fix` command to
upgrade files as needed.
#### We can change our minds
When/if the kustomization struct graduates to some
kind of API status, with an expectation of
"versionless" storage and downgrade capability,
whatever it looks like at that moment can be
locked into `/v1beta1` or `/v1` and the `kind`
and `apiVersion` fields can be required from that
moment forward.
[field change policy]: #field-change-policy
[some range]: https://kubernetes.io/docs/reference/using-api/deprecation-policy
@@ -256,12 +232,11 @@ If missing, the value of `apiVersion` defaults to
[beta-level rules]: https://github.com/kubernetes/community/blob/master/contributors/devel/api_changes.md#alpha-beta-and-stable-versions
[changes]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md
[adapt]: https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/types/kustomization.go#L166
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#resources
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#resources
[k8s API]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
[conventions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
[release page]: https://github.com/kubernetes-sigs/kustomize/releases
[release process]: ../releasing/README.md
[kustomization]: glossary.md#kustomization
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#types-kinds
[`apiVersion`]: https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning
[semantic versioning]: https://semver.org

View File

@@ -33,7 +33,7 @@ chmod u+x kustomize
使用 [Go] v1.10.1 或更高版本安装(如果可以访问 [golang.org]
<!-- @installkustomize @testAgainstLatestRelease -->
<!-- @installkustomize @test -->
```
go install sigs.k8s.io/kustomize/kustomize
go install sigs.k8s.io/kustomize/v3/cmd/kustomize
```

View File

@@ -6,7 +6,7 @@
* [示例](../../examples) - 各种使用流程和概念的详细演示。
* [术语表](glossary.md) - 用于消除术语歧义。
* [术语表](../glossary.md) - 用于消除术语歧义。
* [Kustomize 字段](fields.md) - 介绍 [kustomization](../glossary.md#kustomization) 文件中各字段的含义。
@@ -19,8 +19,6 @@
## 发行说明
* [3.1](../v3.1.0.md) - 2019年7月下旬扩展 patches 和改进的资源匹配。
* [3.0](../v3.0.0.md) - 2019年6月下旬插件开发者发布。
* [2.1](../v2.1.0.md) - 2019年6月18日

View File

@@ -1,308 +0,0 @@
# 词汇表
[CRD spec]: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/
[CRD]: #custom-resource-definition
[DAM]: #声明式应用程序管理
[Declarative Application Management]: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/declarative-application-management.md
[JSON]: https://www.json.org/
[JSONPatch]: https://tools.ietf.org/html/rfc6902
[JSONMergePatch]: https://tools.ietf.org/html/rfc7386
[Resource]: #resource
[YAML]: http://www.yaml.org/start.html
[application]: #application
[apply]: #apply
[apt]: https://en.wikipedia.org/wiki/APT_(Debian)
[base]: #base
[bases]: #base
[bespoke]: #bespoke-configuration
[gitops]: #gitops
[k8s]: #kubernetes
[kubernetes]: #kubernetes
[kustomize]: #kustomize
[kustomization]: #kustomization
[kustomizations]: #kustomization
[off-the-shelf]: #off-the-shelf-configuration
[overlay]: #overlay
[overlays]: #overlay
[patch]: #patch
[patches]: #patch
[patchJson6902]: #patchjson6902
[patchExampleJson6902]: https://github.com/kubernetes-sigs/kustomize/blob/master/examples/jsonpatch.md
[patchesJson6902]: #patchjson6902
[proposal]: https://github.com/kubernetes/community/pull/1629
[rebase]: https://git-scm.com/docs/git-rebase
[资源]: #资源
[resources]: #resource
[root]: #kustomization-root
[rpm]: https://en.wikipedia.org/wiki/Rpm_(software)
[strategic-merge]: https://git.k8s.io/community/contributors/devel/sig-api-machinery/strategic-merge-patch.md
[target]: #target
[transformer]: #transformer
[variant]: #variant
[variants]: #variant
[workflow]: workflows.md
## 应用
**应用**是为某种目的关联起来的一组 Kubernetes 资源,例如一个前有负载均衡器,后有数据库的 Web 服务器。用标签、命名和元数据将[资源]组织起来,可以进行**添加**或**删除**等操作。
有提案([Declarative Application Management])描述了一种称为应用的新的 Kubernetes 资源。更加正式的描述了这一思路,并在应用程序级别提供了运维和仪表盘的支持。
[Kustomize] 对 Kubernetes 资源进行配置,其中描述的应用程序资源只是另一种普通的资源。
## Apply
**Apply** 这个动词在 Kubernetes 的上下文中,指的是一个 Kubernetes 命令以及能够对集群施加影响的进程内 [API 端点](https://goo.gl/UbCRuf)。
用户可以将对集群的运行要求用一组完整的资源列表的形式进行表达,通过 **apply** 命令进行提交。
集群把新提交的资源和之前提交的状态以及当前的实际状态进行合并,形成新的状态。这就是 Kubernetes 的状态管理过程。
## Base
**Base** 指的是会被其它 [Kustomization] 引用的 [Kustomization]。
包括 [Overlay] 在内的任何 Kustomization都可以作为其它 Kustomization 的 Base。
Base 对引用自己的 Overlay 并无感知。
Base 和 [Overlay] 可以作为 Git 仓库中的唯一内容,用于简单的 [GitOps] 管理。对仓库的变更可以触发构建、测试以及部署过程。
## 定制配置
**定制**配置是由组织为满足自身需要,在内部创建和管理的 [Kustomization] 和[资源]。
和**定制配置**关联的 [Workflow] 比关联到通用配置的 [Workflow] 要简单一些,原因是通用配置是共享的,需要周期性的跟踪他人作出的变更。
## Custom resource definition
可以通过定制 CRD ([CRD spec]) 的方式对 Kubernetes API 进行扩展。
CRD 定义的[资源]是一种全新的资源,可以和 ConfigMap、Deployment 之类的原生资源以相同的方式来使用。
Kustomize 能够生成自定义资源,但是要完成这个目标,必须给出对应的 CRD这样才能正确的对这种结构进行处理。
## 声明式应用程序管理
Kustomize 鼓励对声明式应用程序管理([Declarative Application Management])的支持,这种方式是一系列 Kubernetes 集群管理的最佳实践。Kustomize 应该可以:
- 适用于任何配置,例如自有配置、共享配置、无状态、有状态等。
- 支持通用配置,以及创建变体(例如开发、预发布、生产)。
- 开放使用原生 Kubernetes API而不是隐藏它们。
- 不会给版本控制系统和集成的评审和审计工作造成困难。
- 用 Unix 的风格和其它工具进行协作。
- 避免使用模板、领域特定的语言等额外的学习内容。
## 生成器
生成器生成的资源,可以直接使用,也可以输出给转换器([Transformer])。
## GitOps
一种 DevOps 或者 CICD 流程,这种流程以 Git 作为唯一的事实,并且在这种事实发生变化时采取措施(例如构建、测试和部署)。
## Kustomization
**Kustomization** 这个词可以指 `kustomization.yaml` 这个文件,更常见的情况是一个包含了 `kustomization.yaml` 及其所有直接引用文件的相对路径(所有不需要 URL 的本地数据)。
也就是说,如果在 [Kustomize] 的上下文中说到 **Kustomization**,可能是以下的情况之一:
- 一个叫做 `kustomization.yaml` 的文件。
- 一个压缩包(包含 YAML 文件以及它的引用文件)。
- 一个 Git 压缩包。
- 一个 Git 仓库的 URL。
一个 Kustomization 文件包含的[字段](fields.md),分为四个类别:
- `resources`:待定制的现存[资源],示例字段:`resources``crds`
- `generator`:将要创建的**新**资源,示例字段:`configMapGenerator`(传统)、`secretGenerator`(传统)、`generators`v2.1
- `transformer`:对前面提到的新旧资源进行**处理**的方式。示例字段:`namePrefix``nameSuffix``images``commonLabels``patchesJson6902` 等。在 v2.1 中还有更多的 `transformer`
- `meta`:会对上面几种字段产生影响。示例字段:`vars``namespace``apiVersion``kind` 等。
## Kustomization root
直接包含 `kustomization.yaml` 文件的目录。
处理 Kustomization 文件时,可能访问到该目录以内或以外的文件。
像 YAML 资源这样的数据文件,或者用于生成 ConfigMap 或 Secret 的包含 `name=value` 的文本文件,或者用于补丁转换的补丁文件,必须**在这个目录的内部**,需要显式的使用**相对路径**来表达。
v2.1 中有一个特殊选项 `--load_restrictions none` 能够放宽这个限制,从而让不同的 Kustomization 可以共享补丁文件。
可以用 URL、绝对路径或者相对路径引用其它的 Kustomization包含 `kustomization.yaml` 文件的其它目录)。
如果 `A` Kustomization 依赖 `B` Kustomization那么
- `B` 不能包含 `A`
- `B` 不能依赖 `A`,间接依赖也不可以。
`A` 可以包含 `B`,但是这样的话,最简单的方式可能是让 `A` 直接依赖 `B` 的资源,并去除 `B``kustomization.yaml` 文件(就是把 `B` 合并到 `A`)。
通常情况下,`B``A` 处于同级目录,或者 `B` 放在一个完全独立的 Git 仓库里,可以从任意的 Kustomization 进行引用。
常见布局大致如下:
> ```
> ├── base
> │   ├── deployment.yaml
> │   ├── kustomization.yaml
> │   └── service.yaml
> └── overlays
> ├── dev
> │   ├── kustomization.yaml
> │   └── patch.yaml
> ├── prod
> │   ├── kustomization.yaml
> │   └── patch.yaml
> └── staging
> ├── kustomization.yaml
> └── patch.yaml
> ```
`dev``prod` 以及 `staging` 是否依赖于 `base`,要根据 `kustomization.yaml` 具体判断。
## Kubernetes
[Kubernetes](https://kubernetes.io) 是一个开源软件,为容器化应用提供了自动部署、伸缩和管理的能力。
它经常会被简写为 `k8s`
## Kubernetes 风格的对象
[必要字段]: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
用 YAML 或者 JSON 文件表达一个对象,其中包含一些[必要字段]。`kind` 字段用于标识对象类型,`metadata/name` 字段用于区分实例,`apiVersion` 表示的是版本(如果有多个版本的话)。
## Kustomize
`kustomize` 是一个面向 Kubernetes 的命令行工具,用一种无模板、结构化的的方式为为声明式配置提供定制支持。
`面向 Kubernetes` 的意思是 Kustomize 对 API 资源、Kubernetes 概念(例如名称、标签、命名空间等)、以及资源补丁是有支持的。
Kustomize 是 [DAM] 的一个实现。
## 通用配置
通用配置是一种用于共享的 Kustomization 以及资源。
例如创建一个这样的 Github 仓库:
> ```
> github.com/username/someapp/
> kustomization.yaml
> deployment.yaml
> configmap.yaml
> README.md
> ```
其他人可以 `fork` 这个仓库,并把它们的 Fork `clone` 到本地进行定制。
用户可以用这个克隆回来的版本作为 [Base],在此基础上定制 [Overlay] 来满足自身需求。
## Overlay
`Overlay` 是一个 依赖于其它 Kustomization 的 Kustomization。
Overlay 引用通过文件路径、URI 或者别的什么方式)的 [Kustomization] 被称为 [Base]。
Overlay 无法脱离 Base 独立生效。
Overlay 可以作为其它 Overlay 的 Base。
通常 Overlay 都是不止一个的,因为实际情况中就需要为单一 Base 创建不同的[变体],例如 `development``QA``production` 等。
总的说来,这些变体使用的资源基本是一致的,只有一些简单的差异,例如 Deployment 的实例数量、特定 Pod 的 CPU 资源、ConfigMap 中的数据源定义等。
可以这样把配置提交到集群:
> ```
> kustomize build someapp/overlays/staging |\
> kubectl apply -f -
>
> kustomize build someapp/overlays/production |\
> kubectl apply -f -
> ```
对 Base 的使用是隐性的——Overlay 的依赖是指向 Base 的。
请参考 [root]。
## 包
在 Kustomize 中,`包`是没有意义的Kustomize 并无意成为 [apt]、[rpm] 那样的传统包管理工具。
## Patch
修改资源的通用指令。
有两种功能类似但是实现不同的补丁方式:[strategic merge patch](#patchstrategicmerge) 和 [JSON patch](#patchjson6902)。
## patchStrategicMerge
`patchStrategicMerge` 是 [strategic-merge] 风格的补丁SMP
SMP 看上去像个不完整的 Kubernetes 资源 YAML。SMP 中包含 `TypeMeta` 字段,用于表明这个补丁的目标[资源]的 `group/version/kind/name`,剩余的字段是一个嵌套的结构,用于指定新的字段值,例如镜像标签。
缺省情况下SMP 会**替换**目标值。如果目标值是一个字符串,这种行为是合适的,但是如果目标值是个列表,可能就不合适了。
可以加入 `directive` 来修改这种行为,,可以接受的 `directive` 包括 `replace`(缺省)、`merge`(不替换列表)、`delete` 等([相关说明][strategic-merge])。
注意对自定义资源来说SMP 会被当作 [json merge patches][JSONMergePatch].
有趣的事实:所有的资源文件都可以当作 SMP 使用,相同 `group/version/kind/name` 资源中的匹配字段会被替换,其它内容则保持不变。
## patchJson6902
`patchJson6902` 引用一个 Kubernetes 资源,并用 [JSONPatch] 指定了修改这一资源的方法。
`patchJson6902` 几乎可以做到所有 `patchStrategicMerge` 的功能,但是语法更加简单,参考[示例][patchExampleJson6902]
## 插件
Kustomize 可以使用的一段代码,但是无需编译到 Kustomize 内部,可以作为 Kustomization 的一部分,生成或转换 Kubernetes 资源。
[插件](../plugins)的细节。
## 资源
在 REST-ful API 的上下文中,资源是 `GET``PUT` 或者 `POST` 等 HTTP 操作的目标。Kubernetes 提供了 REST-ful API 界面,用于和客户端进行交互。
在 Kustomization 的上下文中,资源是一个相对于 [root] 的相对路径,指向 [YAML] 或者 [JSON] 文件,描述了一个 Kubernetes API 对象,例如 Deployment 或者 ConfigMap或者一个 Kustomization、或者一个指向 Kustomization 的 URL。
或者说任何定义了[对象](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields)的格式正确的 YAML 文件,其中包含了 `kind``metadata/name` 字段,都是资源。
## Root
参看 [kustomization root][root].
## sub-target / sub-application / sub-package
不存在 `sub-xxx`,只有 [Base] 和 [Overlay]。
## Target
`target``kustomize build` 的参数,例如:
> ```
> kustomize build $target
> ```
`$target` 必须是一个指向 [Kustomization] 的路径或者 URL。
要创建用于进行 [Apply] 操作的资源,`target` 中必须包含或者引用所有相关信息。
[Base] 或者 [Overlay] 都可以作为 `target`
## Transformer
转换器能够修改资源,或者在 `kustomize build` 的过程中获取资源的信息。
## 变体
在集群中把 [Overlay] 应用到 [Base] 上的产物称为**变体**。
比如 `staging``production` 两个 Overlay都修改了同样的 Base来创建各自的变体。
`staging` 变体包含了一组用来保障测试过程的资源,或者一些想要看到生产环境下一个版本的外部用户。
`production` 变体用于承载生产流量,可能使用大量的副本,分配更多的 CPU 和内存。

View File

@@ -2,71 +2,71 @@ English | [简体中文](zh/README.md)
# Examples
To run these examples, your `$PATH` must contain `kustomize`.
See the [installation instructions](../docs/INSTALL.md).
These examples assume that `kustomize` is on your `$PATH`.
These examples are [tested](../travis/pre-commit.sh)
to work with the latest _released_ version of kustomize.
They are covered by [pre-commit](../travis/pre-commit.sh)
tests, and should work with HEAD
<!-- @installkustomize @test -->
```
go get sigs.k8s.io/kustomize/v3/cmd/kustomize
```
Basic Usage
* [configGenerations](configGeneration.md) -
Rolling update when ConfigMapGenerator changes.
* [combineConfigs](combineConfigs.md) -
Mixing configuration data from different owners
(e.g. devops/SRE and developers).
* [generatorOptions](generatorOptions.md) -
Modifying behavior of all ConfigMap and Secret generators.
Modifying behavior of all ConfigMap and Secret generators.
* [vars](wordpress/README.md) - Injecting k8s runtime data into
container arguments (e.g. to point wordpress to a SQL service) by vars.
* [image names and tags](image.md) - Updating image names and tags without applying a patch.
* [remote target](remoteBuild.md) - Building a kustomization from a github URL
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
* [patch multiple objects](patchMultipleObjects.md) - Apply a patch to multiple objects
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
Advanced Usage
- generator plugins:
* [last mile helm](chart.md) - Make last mile modifications to
a helm chart.
* [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin.
* [remote sources](goGetterGeneratorPlugin.md) - Generating from remote sources.
* [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin.
- transformer plugins:
* [validation transformer](validationTransformer/README.md) -
validate resources through a transformer
- customize builtin transformer configurations
* [transformer configs](transformerconfigs/README.md) - Customize transformer configurations
Multi Variant Examples
* [hello world](helloWorld/README.md) - Deploy multiple
(differently configured) variants of a simple Hello
World server.
* [LDAP](ldap/README.md) - Deploy multiple
(differently configured) variants of a LDAP server.
* [springboot](springboot/README.md) - Create a Spring Boot
application production configuration from scratch.
* [mySql](mySql/README.md) - Create a MySQL production
configuration from scratch.
* [breakfast](breakfast.md) - Customize breakfast for
Alice and Bob.
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.

View File

@@ -6,14 +6,14 @@
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
Make a place to put the base breakfast configuration:
<!-- @baseDir @testAgainstLatestRelease -->
<!-- @baseDir @test -->
```
mkdir -p $DEMO_HOME/breakfast/base
```
@@ -21,7 +21,7 @@ mkdir -p $DEMO_HOME/breakfast/base
Make a `kustomization` to define what goes into
breakfast. This breakfast has coffee and pancakes:
<!-- @baseKustomization @testAgainstLatestRelease -->
<!-- @baseKustomization @test -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/kustomization.yaml
resources:
@@ -34,7 +34,7 @@ Here's a _coffee_ type. Give it a `kind` and `metdata/name` field
to conform to [kubernetes API object style]; no other
file or definition is needed:
<!-- @coffee @testAgainstLatestRelease -->
<!-- @coffee @test -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/coffee.yaml
kind: Coffee
@@ -50,7 +50,7 @@ The `name` field merely distinguishes this instance of
coffee from others (if there were any).
Likewise, define _pancakes_:
<!-- @pancakes @testAgainstLatestRelease -->
<!-- @pancakes @test -->
```
cat <<EOF >$DEMO_HOME/breakfast/base/pancakes.yaml
kind: Pancakes
@@ -64,7 +64,7 @@ EOF
Make a custom [variant] of breakfast for Alice, who
likes her coffee hot:
<!-- @aliceOverlay @testAgainstLatestRelease -->
<!-- @aliceOverlay @test -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/alice
@@ -87,7 +87,7 @@ EOF
And likewise a [variant] for Bob, who wants _five_ pancakes, with strawberries:
<!-- @bobOverlay @testAgainstLatestRelease -->
<!-- @bobOverlay @test -->
```
mkdir -p $DEMO_HOME/breakfast/overlays/bob
@@ -111,14 +111,14 @@ EOF
One can now generate the configs for Alices breakfast:
<!-- @generateAlice @testAgainstLatestRelease -->
<!-- @generateAlice @test -->
```
kustomize build $DEMO_HOME/breakfast/overlays/alice
```
Likewise for Bob:
<!-- @generateBob @testAgainstLatestRelease -->
<!-- @generateBob @test -->
```
kustomize build $DEMO_HOME/breakfast/overlays/bob
```

View File

@@ -128,7 +128,7 @@ defined in the [helloworld] demo.
It will all live in this work directory:
<!-- @makeWorkplace @testAgainstLatestRelease -->
<!-- @makeWorkplace @test -->
```
DEMO_HOME=$(mktemp -d)
```
@@ -139,7 +139,7 @@ DEMO_HOME=$(mktemp -d)
Make a place to put the base configuration:
<!-- @baseDir @testAgainstLatestRelease -->
<!-- @baseDir @test -->
```
mkdir -p $DEMO_HOME/base
```
@@ -150,7 +150,7 @@ environments. Here we're only defining a java
properties file, and a `kustomization` file that
references it.
<!-- @baseKustomization @testAgainstLatestRelease -->
<!-- @baseKustomization @test -->
```
cat <<EOF >$DEMO_HOME/base/common.properties
color=blue
@@ -171,14 +171,14 @@ EOF
Make an abbreviation for the parent of the overlay
directories:
<!-- @overlays @testAgainstLatestRelease -->
<!-- @overlays @test -->
```
OVERLAYS=$DEMO_HOME/overlays
```
Create the files that define the _development_ overlay:
<!-- @developmentFiles @testAgainstLatestRelease -->
<!-- @developmentFiles @test -->
```
mkdir -p $OVERLAYS/development
@@ -206,7 +206,7 @@ EOF
One can now generate the configMaps for development:
<!-- @runDev @testAgainstLatestRelease -->
<!-- @runDev @test -->
```
kustomize build $OVERLAYS/development
```
@@ -260,7 +260,7 @@ deletes unused configMaps.
Next, create the files for the _production_ overlay:
<!-- @productionFiles @testAgainstLatestRelease -->
<!-- @productionFiles @test -->
```
mkdir -p $OVERLAYS/production
@@ -287,7 +287,7 @@ EOF
One can now generate the configMaps for production:
<!-- @runProd @testAgainstLatestRelease -->
<!-- @runProd @test -->
```
kustomize build $OVERLAYS/production
```

View File

@@ -15,10 +15,8 @@ Kustomize provides two ways of adding ConfigMap in one `kustomization`, either b
> configMapGenerator:
> - name: a-configmap
> files:
> # configfile is used as key
> - configs/configfile
> # configkey is used as key
> - configkey=configs/another_configfile
> - configs/another_configfile
> ```
The ConfigMaps declared as [resource] are treated the same way as other resources. Kustomize doesn't append any hash to the ConfigMap name. The ConfigMap declared from a ConfigMapGenerator is treated differently. A hash is appended to the name and any change in the ConfigMap will trigger a rolling update.
@@ -28,7 +26,7 @@ In this demo, the same [hello_world](helloWorld/README.md) is used while the Con
### Establish base and staging
Establish the base with a configMapGenerator
<!-- @establishBase @testAgainstLatestRelease -->
<!-- @establishBase @test -->
```
DEMO_HOME=$(mktemp -d)
@@ -55,7 +53,7 @@ EOF
```
Establish the staging with a patch applied to the ConfigMap
<!-- @establishStaging @testAgainstLatestRelease -->
<!-- @establishStaging @test -->
```
OVERLAYS=$DEMO_HOME/overlays
mkdir -p $OVERLAYS/staging
@@ -93,7 +91,7 @@ configured with data from a configMap.
The deployment refers to this map by name:
<!-- @showDeployment @testAgainstLatestRelease -->
<!-- @showDeployment @test -->
```
grep -C 2 configMapKeyRef $BASE/deployment.yaml
```
@@ -119,7 +117,7 @@ collected](https://github.com/kubernetes-sigs/kustomize/issues/242).
The _staging_ [variant] here has a configMap [patch]:
<!-- @showMapPatch @testAgainstLatestRelease -->
<!-- @showMapPatch @test -->
```
cat $OVERLAYS/staging/map.yaml
```
@@ -130,7 +128,7 @@ resource spec.
The ConfigMap it modifies is declared from a configMapGenerator.
<!-- @showMapBase @testAgainstLatestRelease -->
<!-- @showMapBase @test -->
```
grep -C 4 configMapGenerator $BASE/kustomization.yaml
```
@@ -143,7 +141,7 @@ _not_ what gets used in the cluster. By design,
kustomize modifies names of ConfigMaps declared from ConfigMapGenerator. To see the names
ultimately used in the cluster, just run kustomize:
<!-- @grepStagingName @testAgainstLatestRelease -->
<!-- @grepStagingName @test -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
@@ -161,7 +159,7 @@ The suffix to the configMap name is generated from a
hash of the maps content - in this case the name suffix
is _k25m8k5k5m_:
<!-- @grepStagingHash @testAgainstLatestRelease -->
<!-- @grepStagingHash @test -->
```
kustomize build $OVERLAYS/staging | grep k25m8k5k5m
```
@@ -169,7 +167,7 @@ kustomize build $OVERLAYS/staging | grep k25m8k5k5m
Now modify the map patch, to change the greeting
the server will use:
<!-- @changeMap @testAgainstLatestRelease -->
<!-- @changeMap @test -->
```
sed -i.bak 's/pineapple/kiwi/' $OVERLAYS/staging/map.yaml
```
@@ -183,7 +181,7 @@ kustomize build $OVERLAYS/staging |\
Run kustomize again to see the new configMap names:
<!-- @grepStagingName @testAgainstLatestRelease -->
<!-- @grepStagingName @test -->
```
kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map
@@ -194,7 +192,7 @@ in three new names ending in _cd7kdh48fd_ - one in the
configMap name itself, and two in the deployment that
uses the map:
<!-- @countHashes @testAgainstLatestRelease -->
<!-- @countHashes @test -->
```
test 3 == \
$(kustomize build $OVERLAYS/staging | grep cd7kdh48fd | wc -l); \

View File

@@ -1,333 +0,0 @@
[builtin operations]: ../docs/plugins/builtins.md
[builtin plugins]: ../docs/plugins/builtins.md
[plugins]: ../docs/plugins
[plugin]: ../docs/plugins
[fields]: ../docs/fields.md
[fields in a kustomization file]: ../docs/fields.md
[TransformerConfig]: ../api/plugins/builtinconfig/transformerconfig.go
[kustomization]: ../docs/glossary.md#kustomization
# Customizing kustomize
The [fields in a kustomization file] allow the user to
specify which resource files to use as input, how to
_generate_ new resources, and how to _transform_ those
resources - add labels, patch them, etc.
These fields are simple (low argument count) directives.
For example, the `commonAnnotations` field demands only a
list of _name:value_ pairs.
If using a field triggers behavior that pleases the user,
everyone's happy.
If not, the user can ask for new behavior to be implemented
in kustomize proper (and wait), or the user can write a
transformer or generator [plugin]. This latter option
generally means writing code; a Go plugin, a Go binary,
a C++ binary, a `bash` script - something.
There's a third option. If one merely wants to tweak
behavior that already exists in kustomize, one may be able
to do so by just writing some YAML.
## Configure the builtin plugins
All of kustomize's [builtin operations] are implemented
and usable as plugins.
Using the fields is convenient and brief, but necessarily
specifies only part of the entire plugin specification. The
unspecified part is defaulted to what are hopefully
generally appealing values.
If, instead, one invokes the plugins directly using the
`transformers` or `generators` field, one can (indeed
_must_) specify the entire plugin configuration.
## Example: field vs plugin
Define a place to work:
<!-- @makeWorkplace @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
```
### Using the `commonLabels` and `commonAnnotations` fields
In this simple example, we'll use just two resources: a deployment and a service.
Define them:
<!-- @makeRes1 @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 10
template:
spec:
containers:
- name: the-container
image: monopole/hello:1
EOF
```
<!-- @makeRes2 @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/service.yaml
apiVersion: v1
kind: Service
metadata:
name: service
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 8666
targetPort: 8080
EOF
```
Now make a kustomization file that causes them
to be read and transformed:
<!-- @makeKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
namePrefix: hello-
commonLabels:
app: hello
commonAnnotations:
area: "51"
greeting: Take me to your leader
resources:
- deployment.yaml
- service.yaml
EOF
```
And run kustomize:
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
The output will be something like
> ```
> apiVersion: v1
> kind: Service
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> name: hello-service
> spec:
> ports:
> - port: 8666
> protocol: TCP
> targetPort: 8080
> selector:
> app: hello
> type: LoadBalancer
> ---
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> name: hello-deployment
> spec:
> replicas: 10
> selector:
> matchLabels:
> app: hello
> template:
> metadata:
> annotations:
> area: "51"
> greeting: Take me to your leader
> labels:
> app: hello
> spec:
> containers:
> - image: monopole/hello:1
> name: the-container
> ```
Let's say we are unhappy with this result.
We only want the annotations
to be applied down in the pod templates,
and don't want to see them in the metadata
for Service or Deployment.
We like that the label _app: hello_ ended up in
- Service `spec.selector`
- Deployment `spec.selector.matchLabels`
- Deployment `spec.template.metadata.labels`
as this binds the Service (load balancer) to the pods,
and the Deployment itself to its own pods -
but we again don't care to see these labels in
the metadata for the Service and the Deployment.
### Configuring the builtin plugins instead
To fine tune this, invoke the same transformations
using the plugin approach.
Change the kustomization file:
<!-- @makeKustomization @testAgainstLatestRelease -->
```
cat <<'EOF' >$DEMO_HOME/kustomization.yaml
namePrefix: hello-
transformers:
- myAnnotator.yaml
- myLabeller.yaml
resources:
- deployment.yaml
- service.yaml
EOF
```
Then make the two plugin configuration files
(`myAnnotator.yaml`, `myLabeller.yaml`)
referred to by the `transformers` field above.
For details about the fields to specify, see
the documentation for the [builtin plugins].
<!-- @makeAnnotatorPluginConfig @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/myAnnotator.yaml
apiVersion: builtin
kind: AnnotationsTransformer
metadata:
name: notImportantHere
annotations:
area: 51
greeting: take me to your leader
fieldSpecs:
- kind: Deployment
path: spec/template/metadata/annotations
create: true
EOF
```
<!-- @makeLabelPluginConfig @testAgainstLatestRelease -->
```
cat <<EOF >$DEMO_HOME/myLabeller.yaml
apiVersion: builtin
kind: LabelTransformer
metadata:
name: notImportantHere
labels:
app: hello
fieldSpecs:
- kind: Service
path: spec/selector
create: true
- kind: Deployment
path: spec/selector/matchLabels
create: true
- kind: Deployment
path: spec/template/metadata/labels
create: true
EOF
```
Finally, run kustomize again:
<!-- @checkLabel @testAgainstLatestRelease -->
```
kustomize build $DEMO_HOME
```
The output should resemble the following,
with fewer labels and annotations.
> ```
> apiVersion: v1
> kind: Service
> metadata:
> name: hello-service
> spec:
> ports:
> - port: 8666
> protocol: TCP
> targetPort: 8080
> selector:
> app: hello
> type: LoadBalancer
> ---
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: hello-deployment
> spec:
> replicas: 10
> selector:
> matchLabels:
> app: hello
> template:
> metadata:
> annotations:
> area: "51"
> greeting: take me to your leader
> labels:
> app: hello
> spec:
> containers:
> - image: monopole/hello:1
> name: the-container
> ```
## The old way to do this
The original (and still functional) way to customize
kustomize is to specify a `configurations` field in the
kustomization file.
This field, normally omitted because it overrides hardcoded
data, accepts a list of file path arguments. The files, in
turn, specify which fields in which k8s objects should be
affected by particular builtin transformations. It's a
global configuration cutting across transformations, and
doesn't effect generators at all.
At `build` time, the configuration files are unmarshalled
into one instance of [TransformerConfig]. This
object, _plus_ the field values for `namePrefix`, etc. are
fed into the transformation code to build the output.
The best way to write these custom configuration files is to
generate the files from the hardcoded values built into
kustomize via these commands:
> ```
> mkdir /tmp/junk
> kustomize config save -d /tmp/junk
> ```
One can then edit those file or files, and specify the
resulting edited files in a `configurations:`
field in a kustomization file used in a `build`.
Using plugins _completely ignores_ both hard coded
tranformer configuration, and any configuration loaded by
the `configuration` field.

View File

@@ -13,7 +13,7 @@ DEMO_HOME=$(mktemp -d)
Create a kustomization and add a ConfigMap generator to it.
<!-- @createCMGenerator @testAgainstLatestRelease -->
<!-- @createCMGenerator @test -->
```
cat > $DEMO_HOME/kustomization.yaml << EOF
configMapGenerator:
@@ -25,7 +25,7 @@ EOF
```
Add following generatorOptions
<!-- @addGeneratorOptions @testAgainstLatestRelease -->
<!-- @addGeneratorOptions @test -->
```
cat >> $DEMO_HOME/kustomization.yaml << EOF
generatorOptions:
@@ -39,7 +39,7 @@ EOF
Run `kustomize build` and make sure that the generated ConfigMap
- doesn't have name suffix
<!-- @verify @testAgainstLatestRelease -->
<!-- @verify @test -->
```
test 1 == \
$(kustomize build $DEMO_HOME | grep "name: my-configmap$" | wc -l); \

Some files were not shown because too many files have changed in this diff Show More