mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-29 01:30:51 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c464fb0a81 | ||
|
|
694cf23df8 | ||
|
|
e66656aa7f | ||
|
|
eaae7af5fe | ||
|
|
f9fe138114 | ||
|
|
2a2a889c37 | ||
|
|
34287e511f | ||
|
|
e6fffc8ba4 | ||
|
|
86f221611e | ||
|
|
b4d6e89fa2 | ||
|
|
5937bd0259 | ||
|
|
ed3c29be12 | ||
|
|
3d2e956b19 | ||
|
|
dd9d1f95e9 | ||
|
|
a279c08f7d | ||
|
|
a798109161 | ||
|
|
bafd6b5423 | ||
|
|
963913f9ef | ||
|
|
46905588ac | ||
|
|
5426888df4 | ||
|
|
35481ec6d9 | ||
|
|
6c92c30e94 | ||
|
|
02f6b3ec98 | ||
|
|
a9848f2738 | ||
|
|
b4038a6cd2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
/kustomize
|
||||||
|
|
||||||
# Test binary, build with `go test -c`
|
# Test binary, build with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|||||||
28
Makefile
Normal file
28
Makefile
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
BIN_NAME=kustomize
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
clean:
|
||||||
|
go clean
|
||||||
|
rm -f $(BIN_NAME)
|
||||||
|
|
||||||
|
.PHONY: test build install clean generate-code test-go test-lint
|
||||||
14
README.md
14
README.md
@@ -24,8 +24,16 @@ these [instructions](docs/INSTALL.md).
|
|||||||
Browse the [docs](docs) or jump right into the
|
Browse the [docs](docs) or jump right into the
|
||||||
tested [examples](examples).
|
tested [examples](examples).
|
||||||
|
|
||||||
kustomize [v2.0.3] is available in [kubectl v1.14 and v1.15][kubectl].
|
## kubectl integration
|
||||||
|
|
||||||
|
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
|
||||||
|
|
||||||
|
| kubectl version | kustomize version |
|
||||||
|
|---------|--------|
|
||||||
|
| 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
|
## Usage
|
||||||
|
|
||||||
@@ -161,7 +169,9 @@ is governed by the [Kubernetes Code of Conduct].
|
|||||||
[imageBase]: docs/images/base.jpg
|
[imageBase]: docs/images/base.jpg
|
||||||
[imageOverlay]: docs/images/overlay.jpg
|
[imageOverlay]: docs/images/overlay.jpg
|
||||||
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/labels/kind%2Ffeature
|
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/labels/kind%2Ffeature
|
||||||
[kubectl]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
[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/
|
||||||
[kubernetes style]: docs/glossary.md#kubernetes-style-object
|
[kubernetes style]: docs/glossary.md#kubernetes-style-object
|
||||||
[kustomization]: docs/glossary.md#kustomization
|
[kustomization]: docs/glossary.md#kustomization
|
||||||
[overlay]: docs/glossary.md#overlay
|
[overlay]: docs/glossary.md#overlay
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ What transformations (customizations) should be applied?
|
|||||||
| [namePrefix](#nameprefix) | string | Prepends value to the names of all resources |
|
| [namePrefix](#nameprefix) | string | Prepends value to the names of all resources |
|
||||||
| [nameSuffix](#namesuffix) | string | The value is appended 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. |
|
| [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.|
|
|[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.|
|
|[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|
|
|[transformers](#transformers)|list|[plugin](plugins) configuration files|
|
||||||
@@ -263,11 +264,47 @@ resource type is ConfigMap or Secret.
|
|||||||
nameSuffix: -v2
|
nameSuffix: -v2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 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$`.
|
||||||
|
|
||||||
### patchesStrategicMerge
|
### patchesStrategicMerge
|
||||||
|
|
||||||
Each entry in this list should be a relative path
|
Each entry in this list should be either a relative
|
||||||
|
file path or an inline content
|
||||||
resolving to a partial or complete resource
|
resolving to a partial or complete resource
|
||||||
definition file.
|
definition.
|
||||||
|
|
||||||
The names in these (possibly partial) resource
|
The names in these (possibly partial) resource
|
||||||
files must match names already loaded via the
|
files must match names already loaded via the
|
||||||
@@ -286,6 +323,22 @@ patchesStrategicMerge:
|
|||||||
- deployment_increase_memory.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
|
||||||
|
```
|
||||||
|
|
||||||
### patchesJson6902
|
### patchesJson6902
|
||||||
|
|
||||||
Each entry in this list should resolve to
|
Each entry in this list should resolve to
|
||||||
@@ -330,6 +383,23 @@ patchesJson6902:
|
|||||||
path: add_service_annotation.yaml
|
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"
|
||||||
|
```
|
||||||
|
|
||||||
### replicas
|
### replicas
|
||||||
|
|
||||||
Replicas modified the number of replicas for a resource.
|
Replicas modified the number of replicas for a resource.
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
## 发行说明
|
## 发行说明
|
||||||
|
|
||||||
|
* [3.1](../v3.1.0.md) - 2019年7月下旬,扩展 patches 和改进的资源匹配。
|
||||||
|
|
||||||
* [3.0](../v3.0.0.md) - 2019年6月下旬,插件开发者发布。
|
* [3.0](../v3.0.0.md) - 2019年6月下旬,插件开发者发布。
|
||||||
|
|
||||||
* [2.1](../v2.1.0.md) - 2019年6月18日
|
* [2.1](../v2.1.0.md) - 2019年6月18日
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ go get sigs.k8s.io/kustomize/v3/cmd/kustomize
|
|||||||
|
|
||||||
* [json patch](jsonpatch.md) -在 kustomization 中应用 json patch 。
|
* [json patch](jsonpatch.md) -在 kustomization 中应用 json patch 。
|
||||||
|
|
||||||
|
* [patch multiple objects](patchMultipleObjects.md) - 通过一个patch来修改多个资源。
|
||||||
|
|
||||||
高级用法
|
高级用法
|
||||||
|
|
||||||
- generator 插件:
|
- generator 插件:
|
||||||
@@ -34,6 +36,10 @@ go get sigs.k8s.io/kustomize/v3/cmd/kustomize
|
|||||||
|
|
||||||
* [secret generation](../secretGeneratorPlugin.md) - 生成 Secret。
|
* [secret generation](../secretGeneratorPlugin.md) - 生成 Secret。
|
||||||
|
|
||||||
|
- transformer 插件:
|
||||||
|
|
||||||
|
* [validation transformer](../validationTransformer/README.md) - 通过 transformer 验证资源。
|
||||||
|
|
||||||
- 定制内建 transformer 配置
|
- 定制内建 transformer 配置
|
||||||
|
|
||||||
* [transformer configs](../transformerconfigs/README.md) - 自定义 transformer 配置。
|
* [transformer configs](../transformerconfigs/README.md) - 自定义 transformer 配置。
|
||||||
|
|||||||
1
go.sum
1
go.sum
@@ -149,7 +149,6 @@ k8s.io/klog v0.3.3 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c=
|
|||||||
k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
|
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
|
||||||
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
|
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
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 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ func determineFieldOrder() []string {
|
|||||||
"GeneratorOptions",
|
"GeneratorOptions",
|
||||||
"Vars",
|
"Vars",
|
||||||
"Images",
|
"Images",
|
||||||
|
"Replicas",
|
||||||
"Configurations",
|
"Configurations",
|
||||||
"Generators",
|
"Generators",
|
||||||
"Transformers",
|
"Transformers",
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ func TestFieldOrder(t *testing.T) {
|
|||||||
"GeneratorOptions",
|
"GeneratorOptions",
|
||||||
"Vars",
|
"Vars",
|
||||||
"Images",
|
"Images",
|
||||||
|
"Replicas",
|
||||||
"Configurations",
|
"Configurations",
|
||||||
"Generators",
|
"Generators",
|
||||||
"Transformers",
|
"Transformers",
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "no 'git' program on path")
|
return errors.Wrap(err, "no 'git' program on path")
|
||||||
}
|
}
|
||||||
repoSpec.cloneDir, err = fs.NewTmpConfirmedDir()
|
repoSpec.Dir, err = fs.NewTmpConfirmedDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd := exec.Command(
|
cmd := exec.Command(
|
||||||
gitProgram,
|
gitProgram,
|
||||||
"init",
|
"init",
|
||||||
repoSpec.cloneDir.String())
|
repoSpec.Dir.String())
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
@@ -50,7 +50,7 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
return errors.Wrapf(
|
return errors.Wrapf(
|
||||||
err,
|
err,
|
||||||
"trouble initializing empty git repo in %s",
|
"trouble initializing empty git repo in %s",
|
||||||
repoSpec.cloneDir.String())
|
repoSpec.Dir.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = exec.Command(
|
cmd = exec.Command(
|
||||||
@@ -60,7 +60,7 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
"origin",
|
"origin",
|
||||||
repoSpec.CloneSpec())
|
repoSpec.CloneSpec())
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Dir = repoSpec.cloneDir.String()
|
cmd.Dir = repoSpec.Dir.String()
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(
|
return errors.Wrapf(
|
||||||
@@ -68,20 +68,20 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
"trouble adding remote %s",
|
"trouble adding remote %s",
|
||||||
repoSpec.CloneSpec())
|
repoSpec.CloneSpec())
|
||||||
}
|
}
|
||||||
if repoSpec.ref == "" {
|
if repoSpec.Ref == "" {
|
||||||
repoSpec.ref = "master"
|
repoSpec.Ref = "master"
|
||||||
}
|
}
|
||||||
cmd = exec.Command(
|
cmd = exec.Command(
|
||||||
gitProgram,
|
gitProgram,
|
||||||
"fetch",
|
"fetch",
|
||||||
"--depth=1",
|
"--depth=1",
|
||||||
"origin",
|
"origin",
|
||||||
repoSpec.ref)
|
repoSpec.Ref)
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Dir = repoSpec.cloneDir.String()
|
cmd.Dir = repoSpec.Dir.String()
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "trouble fetching %s", repoSpec.ref)
|
return errors.Wrapf(err, "trouble fetching %s", repoSpec.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = exec.Command(
|
cmd = exec.Command(
|
||||||
@@ -90,11 +90,11 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
"--hard",
|
"--hard",
|
||||||
"FETCH_HEAD")
|
"FETCH_HEAD")
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Dir = repoSpec.cloneDir.String()
|
cmd.Dir = repoSpec.Dir.String()
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(
|
return errors.Wrapf(
|
||||||
err, "trouble hard resetting empty repository to %s", repoSpec.ref)
|
err, "trouble hard resetting empty repository to %s", repoSpec.Ref)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
|
|||||||
// used in a test.
|
// used in a test.
|
||||||
func DoNothingCloner(dir fs.ConfirmedDir) Cloner {
|
func DoNothingCloner(dir fs.ConfirmedDir) Cloner {
|
||||||
return func(rs *RepoSpec) error {
|
return func(rs *RepoSpec) error {
|
||||||
rs.cloneDir = dir
|
rs.Dir = dir
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,36 +39,36 @@ type RepoSpec struct {
|
|||||||
raw string
|
raw string
|
||||||
|
|
||||||
// Host, e.g. github.com
|
// Host, e.g. github.com
|
||||||
host string
|
Host string
|
||||||
|
|
||||||
// orgRepo name (organization/repoName),
|
// orgRepo name (organization/repoName),
|
||||||
// e.g. kubernetes-sigs/kustomize
|
// e.g. kubernetes-sigs/kustomize
|
||||||
orgRepo string
|
OrgRepo string
|
||||||
|
|
||||||
// ConfirmedDir where the orgRepo is cloned to.
|
// Dir where the orgRepo is cloned to.
|
||||||
cloneDir fs.ConfirmedDir
|
Dir fs.ConfirmedDir
|
||||||
|
|
||||||
// Relative path in the repository, and in the cloneDir,
|
// Relative path in the repository, and in the cloneDir,
|
||||||
// to a Kustomization.
|
// to a Kustomization.
|
||||||
path string
|
Path string
|
||||||
|
|
||||||
// Branch or tag reference.
|
// Branch or tag reference.
|
||||||
ref string
|
Ref string
|
||||||
|
|
||||||
// e.g. .git or empty in case of _git is present
|
// e.g. .git or empty in case of _git is present
|
||||||
gitSuffix string
|
GitSuffix string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneSpec returns a string suitable for "git clone {spec}".
|
// CloneSpec returns a string suitable for "git clone {spec}".
|
||||||
func (x *RepoSpec) CloneSpec() string {
|
func (x *RepoSpec) CloneSpec() string {
|
||||||
if isAzureHost(x.host) || isAWSHost(x.host) {
|
if isAzureHost(x.Host) || isAWSHost(x.Host) {
|
||||||
return x.host + x.orgRepo
|
return x.Host + x.OrgRepo
|
||||||
}
|
}
|
||||||
return x.host + x.orgRepo + x.gitSuffix
|
return x.Host + x.OrgRepo + x.GitSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RepoSpec) CloneDir() fs.ConfirmedDir {
|
func (x *RepoSpec) CloneDir() fs.ConfirmedDir {
|
||||||
return x.cloneDir
|
return x.Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RepoSpec) Raw() string {
|
func (x *RepoSpec) Raw() string {
|
||||||
@@ -76,11 +76,11 @@ func (x *RepoSpec) Raw() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (x *RepoSpec) AbsPath() string {
|
func (x *RepoSpec) AbsPath() string {
|
||||||
return x.cloneDir.Join(x.path)
|
return x.Dir.Join(x.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *RepoSpec) Cleaner(fSys fs.FileSystem) func() error {
|
func (x *RepoSpec) Cleaner(fSys fs.FileSystem) func() error {
|
||||||
return func() error { return fSys.RemoveAll(x.cloneDir.String()) }
|
return func() error { return fSys.RemoveAll(x.Dir.String()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// From strings like git@github.com:someOrg/someRepo.git or
|
// From strings like git@github.com:someOrg/someRepo.git or
|
||||||
@@ -98,8 +98,8 @@ func NewRepoSpecFromUrl(n string) (*RepoSpec, error) {
|
|||||||
return nil, fmt.Errorf("url lacks host: %s", n)
|
return nil, fmt.Errorf("url lacks host: %s", n)
|
||||||
}
|
}
|
||||||
return &RepoSpec{
|
return &RepoSpec{
|
||||||
raw: n, host: host, orgRepo: orgRepo,
|
raw: n, Host: host, OrgRepo: orgRepo,
|
||||||
cloneDir: notCloned, path: path, ref: gitRef, gitSuffix: gitSuffix}, nil
|
Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: gitSuffix}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -72,17 +72,17 @@ func TestNewRepoSpecFromUrl(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("problem %v", err)
|
t.Errorf("problem %v", err)
|
||||||
}
|
}
|
||||||
if rs.host != hostSpec {
|
if rs.Host != hostSpec {
|
||||||
bad = append(bad, []string{"host", uri, rs.host, hostSpec})
|
bad = append(bad, []string{"host", uri, rs.Host, hostSpec})
|
||||||
}
|
}
|
||||||
if rs.orgRepo != orgRepo {
|
if rs.OrgRepo != orgRepo {
|
||||||
bad = append(bad, []string{"orgRepo", uri, rs.orgRepo, orgRepo})
|
bad = append(bad, []string{"orgRepo", uri, rs.OrgRepo, orgRepo})
|
||||||
}
|
}
|
||||||
if rs.path != pathName {
|
if rs.Path != pathName {
|
||||||
bad = append(bad, []string{"path", uri, rs.path, pathName})
|
bad = append(bad, []string{"path", uri, rs.Path, pathName})
|
||||||
}
|
}
|
||||||
if rs.ref != hrefArg {
|
if rs.Ref != hrefArg {
|
||||||
bad = append(bad, []string{"ref", uri, rs.ref, hrefArg})
|
bad = append(bad, []string{"ref", uri, rs.Ref, hrefArg})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,9 +201,9 @@ func TestNewRepoSpecFromUrl_CloneSpecs(t *testing.T) {
|
|||||||
t.Errorf("AbsPath expected to be %v, but got %v on %s",
|
t.Errorf("AbsPath expected to be %v, but got %v on %s",
|
||||||
testcase.absPath, rs.AbsPath(), testcase.input)
|
testcase.absPath, rs.AbsPath(), testcase.input)
|
||||||
}
|
}
|
||||||
if rs.ref != testcase.ref {
|
if rs.Ref != testcase.ref {
|
||||||
t.Errorf("ref expected to be %v, but got %v on %s",
|
t.Errorf("ref expected to be %v, but got %v on %s",
|
||||||
testcase.ref, rs.ref, testcase.input)
|
testcase.ref, rs.Ref, testcase.input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,11 +138,16 @@ func (th *KustTestHarness) ErrorFromLoadAndRunTransformer(
|
|||||||
|
|
||||||
func (th *KustTestHarness) RunTransformer(
|
func (th *KustTestHarness) RunTransformer(
|
||||||
config, input string) (resmap.ResMap, error) {
|
config, input string) (resmap.ResMap, error) {
|
||||||
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
resMap, err := th.rf.NewResMapFromBytes([]byte(input))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
th.t.Fatalf("Err: %v", err)
|
th.t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
resMap, err := th.rf.NewResMapFromBytes([]byte(input))
|
return th.RunTransformerFromResMap(config, resMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (th *KustTestHarness) RunTransformerFromResMap(
|
||||||
|
config string, resMap resmap.ResMap) (resmap.ResMap, error) {
|
||||||
|
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
th.t.Fatalf("Err: %v", err)
|
th.t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -552,7 +552,7 @@ func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
|||||||
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
||||||
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||||
inputRes *resource.Resource) ResMap {
|
inputRes *resource.Resource) ResMap {
|
||||||
result := New()
|
result := newOne()
|
||||||
inputId := inputRes.CurId()
|
inputId := inputRes.CurId()
|
||||||
isInputIdNamespaceable := inputId.IsNamespaceableKind()
|
isInputIdNamespaceable := inputId.IsNamespaceableKind()
|
||||||
rctxm := inputRes.PrefixesSuffixesEquals
|
rctxm := inputRes.PrefixesSuffixesEquals
|
||||||
@@ -563,15 +563,16 @@ func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
|||||||
resId := r.CurId()
|
resId := r.CurId()
|
||||||
if (!isInputIdNamespaceable || !resId.IsNamespaceableKind() || resId.IsNsEquals(inputId)) &&
|
if (!isInputIdNamespaceable || !resId.IsNamespaceableKind() || resId.IsNsEquals(inputId)) &&
|
||||||
r.InSameKustomizeCtx(rctxm) {
|
r.InSameKustomizeCtx(rctxm) {
|
||||||
err := result.Append(r)
|
result.append(r)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *resWrangler) append(res *resource.Resource) {
|
||||||
|
m.rList = append(m.rList, res)
|
||||||
|
}
|
||||||
|
|
||||||
// AppendAll implements ResMap.
|
// AppendAll implements ResMap.
|
||||||
func (m *resWrangler) AppendAll(other ResMap) error {
|
func (m *resWrangler) AppendAll(other ResMap) error {
|
||||||
if other == nil {
|
if other == nil {
|
||||||
@@ -650,11 +651,18 @@ func (m *resWrangler) appendReplaceOrMerge(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func anchorRegex(pattern string) string {
|
||||||
|
if pattern == "" {
|
||||||
|
return pattern
|
||||||
|
}
|
||||||
|
return "^" + pattern + "$"
|
||||||
|
}
|
||||||
|
|
||||||
// Select returns a list of resources that
|
// Select returns a list of resources that
|
||||||
// are selected by a Selector
|
// are selected by a Selector
|
||||||
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
|
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
|
||||||
ns := regexp.MustCompile(s.Namespace)
|
ns := regexp.MustCompile(anchorRegex(s.Namespace))
|
||||||
nm := regexp.MustCompile(s.Name)
|
nm := regexp.MustCompile(anchorRegex(s.Name))
|
||||||
var result []*resource.Resource
|
var result []*resource.Resource
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
curId := r.CurId()
|
curId := r.CurId()
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ metadata:
|
|||||||
app: name3
|
app: name3
|
||||||
annotations:
|
annotations:
|
||||||
bar: baz
|
bar: baz
|
||||||
|
---
|
||||||
|
apiVersion: group1/v1
|
||||||
|
kind: Kind2
|
||||||
|
metadata:
|
||||||
|
name: x-name1
|
||||||
|
namespace: x-default
|
||||||
`))
|
`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error %v", err)
|
t.Fatalf("unexpected error %v", err)
|
||||||
@@ -56,13 +62,13 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "name*",
|
Name: "name.*",
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "name*",
|
Name: "name.*",
|
||||||
AnnotationSelector: "foo=bar",
|
AnnotationSelector: "foo=bar",
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
@@ -78,7 +84,7 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
Gvk: gvk.Gvk{
|
Gvk: gvk.Gvk{
|
||||||
Kind: "Kind1",
|
Kind: "Kind1",
|
||||||
},
|
},
|
||||||
Name: "name*",
|
Name: "name.*",
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
@@ -92,7 +98,7 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "",
|
Name: "",
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
@@ -104,18 +110,60 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
Name: "name*",
|
Name: "name.*",
|
||||||
Gvk: gvk.Gvk{
|
Gvk: gvk.Gvk{
|
||||||
Kind: "Kind1",
|
Kind: "Kind1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Name: "^name.*",
|
||||||
|
},
|
||||||
|
count: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Name: "name.*$",
|
||||||
|
},
|
||||||
|
count: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Name: "^name.*$",
|
||||||
|
},
|
||||||
|
count: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Namespace: "^def.*",
|
||||||
|
},
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Namespace: "def.*$",
|
||||||
|
},
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Namespace: "^def.*$",
|
||||||
|
},
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: types.Selector{
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
actual, err := rm.Select(testcase.target)
|
actual, err := rm.Select(testcase.target)
|
||||||
|
|||||||
243
pkg/target/inlinepatch_test.go
Normal file
243
pkg/target/inlinepatch_test.go
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package target_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
`)
|
||||||
|
}
|
||||||
@@ -156,7 +156,7 @@ func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
|
|||||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||||
c.Target = *args.Target
|
c.Target = *args.Target
|
||||||
c.Path = args.Path
|
c.Path = args.Path
|
||||||
c.JsonOp = "" // Not implemented for kustomization file yet.
|
c.JsonOp = args.Patch
|
||||||
p := builtin.NewPatchJson6902TransformerPlugin()
|
p := builtin.NewPatchJson6902TransformerPlugin()
|
||||||
err = kt.configureBuiltinPlugin(p, c, "patchJson6902")
|
err = kt.configureBuiltinPlugin(p, c, "patchJson6902")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -178,7 +178,6 @@ func (kt *KustTarget) configureBuiltinPatchStrategicMergeTransformer(
|
|||||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
}
|
}
|
||||||
c.Paths = kt.kustomization.PatchesStrategicMerge
|
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||||
c.Patches = "" // Not implemented for kustomization file yet
|
|
||||||
p := builtin.NewPatchStrategicMergeTransformerPlugin()
|
p := builtin.NewPatchStrategicMergeTransformerPlugin()
|
||||||
err = kt.configureBuiltinPlugin(p, c, "patchStrategicMerge")
|
err = kt.configureBuiltinPlugin(p, c, "patchStrategicMerge")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -331,6 +331,9 @@ type PatchJson6902 struct {
|
|||||||
|
|
||||||
// relative file path for a json patch file inside a kustomization
|
// relative file path for a json patch file inside a kustomization
|
||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
|
||||||
|
// inline patch string
|
||||||
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatchTarget represents the kubernetes object that the patch is applied to
|
// PatchTarget represents the kubernetes object that the patch is applied to
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type PatchStrategicMergeTransformerPlugin struct {
|
|||||||
rf *resmap.Factory
|
rf *resmap.Factory
|
||||||
loadedPatches []*resource.Resource
|
loadedPatches []*resource.Resource
|
||||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
Patches string `json:patches,omitempty" yaml:"patches,omitempty"`
|
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection GoUnusedGlobalVariable
|
//noinspection GoUnusedGlobalVariable
|
||||||
@@ -35,11 +35,18 @@ func (p *PatchStrategicMergeTransformerPlugin) Config(
|
|||||||
return fmt.Errorf("empty file path and empty patch content")
|
return fmt.Errorf("empty file path and empty patch content")
|
||||||
}
|
}
|
||||||
if len(p.Paths) != 0 {
|
if len(p.Paths) != 0 {
|
||||||
res, err := p.rf.RF().SliceFromPatches(ldr, p.Paths)
|
for _, onePath := range p.Paths {
|
||||||
if err != nil {
|
res, err := p.rf.RF().SliceFromBytes([]byte(onePath))
|
||||||
return err
|
if err == nil {
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res, err = p.rf.RF().SliceFromPatches(ldr, []types.PatchStrategicMerge{onePath})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
}
|
}
|
||||||
p.loadedPatches = res
|
|
||||||
}
|
}
|
||||||
if p.Patches != "" {
|
if p.Patches != "" {
|
||||||
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
||||||
|
|||||||
@@ -34,8 +34,15 @@ func (p *ReplicaCountTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
|
|
||||||
|
found := false
|
||||||
for i, replicaSpec := range p.FieldSpecs {
|
for i, replicaSpec := range p.FieldSpecs {
|
||||||
for _, res := range m.GetMatchingResourcesByOriginalId(p.createMatcher(i)) {
|
matcher := p.createMatcher(i)
|
||||||
|
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
|
||||||
|
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher)
|
||||||
|
|
||||||
|
for _, res := range append(matchOriginal, matchCurrent...) {
|
||||||
|
found = true
|
||||||
err := transformers.MutateField(
|
err := transformers.MutateField(
|
||||||
res.Map(), replicaSpec.PathSlice(),
|
res.Map(), replicaSpec.PathSlice(),
|
||||||
replicaSpec.CreateIfNotPresent, p.addReplicas)
|
replicaSpec.CreateIfNotPresent, p.addReplicas)
|
||||||
@@ -45,6 +52,15 @@ func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
gvks := make([]string, len(p.FieldSpecs))
|
||||||
|
for i, replicaSpec := range p.FieldSpecs {
|
||||||
|
gvks[i] = replicaSpec.Gvk.String()
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Resource with name %s does not match a config with the following GVK %v",
|
||||||
|
p.Replica.Name, gvks)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ spec:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchJson6902TransformerWithInline(t *testing.T) {
|
func TestPatchJson6902TransformerWithInlineJSON(t *testing.T) {
|
||||||
tc := plugins_test.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
@@ -290,3 +290,47 @@ spec:
|
|||||||
dnsPolicy: ClusterFirst
|
dnsPolicy: ClusterFirst
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchJson6902TransformerWithInlineYAML(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
jsonOp: |-
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/dnsPolicy
|
||||||
|
value: ClusterFirst
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
dnsPolicy: ClusterFirst
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type plugin struct {
|
|||||||
rf *resmap.Factory
|
rf *resmap.Factory
|
||||||
loadedPatches []*resource.Resource
|
loadedPatches []*resource.Resource
|
||||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
Patches string `json:patches,omitempty" yaml:"patches,omitempty"`
|
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection GoUnusedGlobalVariable
|
//noinspection GoUnusedGlobalVariable
|
||||||
@@ -36,11 +36,18 @@ func (p *plugin) Config(
|
|||||||
return fmt.Errorf("empty file path and empty patch content")
|
return fmt.Errorf("empty file path and empty patch content")
|
||||||
}
|
}
|
||||||
if len(p.Paths) != 0 {
|
if len(p.Paths) != 0 {
|
||||||
res, err := p.rf.RF().SliceFromPatches(ldr, p.Paths)
|
for _, onePath := range p.Paths {
|
||||||
if err != nil {
|
res, err := p.rf.RF().SliceFromBytes([]byte(onePath))
|
||||||
return err
|
if err == nil {
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res, err = p.rf.RF().SliceFromPatches(ldr, []types.PatchStrategicMerge{onePath})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
}
|
}
|
||||||
p.loadedPatches = res
|
|
||||||
}
|
}
|
||||||
if p.Patches != "" {
|
if p.Patches != "" {
|
||||||
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ paths:
|
|||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(),
|
if !strings.Contains(err.Error(),
|
||||||
"cannot read file \"/app/patch.yaml\"") {
|
"cannot read file \"/app/patch.yaml\"") &&
|
||||||
|
!strings.Contains(err.Error(),
|
||||||
|
"cannot unmarshal string") {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +183,7 @@ spec:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchStrategicMergeTransformerWithInline(t *testing.T) {
|
func TestPatchStrategicMergeTransformerWithInlineJSON(t *testing.T) {
|
||||||
tc := plugins_test.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
@@ -216,6 +218,58 @@ spec:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchStrategicMergeTransformerWithInlineYAML(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchStrategicMergeTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchStrategicMergeTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
patches: |-
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:latest
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPatchStrategicMergeTransformerMultiplePatches(t *testing.T) {
|
func TestPatchStrategicMergeTransformerMultiplePatches(t *testing.T) {
|
||||||
tc := plugins_test.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
@@ -1226,4 +1280,4 @@ paths:
|
|||||||
`, target)
|
`, target)
|
||||||
|
|
||||||
th.AssertActualEqualsExpected(rm, ``)
|
th.AssertActualEqualsExpected(rm, ``)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,15 @@ func (p *plugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
|
|
||||||
|
found := false
|
||||||
for i, replicaSpec := range p.FieldSpecs {
|
for i, replicaSpec := range p.FieldSpecs {
|
||||||
for _, res := range m.GetMatchingResourcesByOriginalId(p.createMatcher(i)) {
|
matcher := p.createMatcher(i)
|
||||||
|
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
|
||||||
|
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher)
|
||||||
|
|
||||||
|
for _, res := range append(matchOriginal, matchCurrent...) {
|
||||||
|
found = true
|
||||||
err := transformers.MutateField(
|
err := transformers.MutateField(
|
||||||
res.Map(), replicaSpec.PathSlice(),
|
res.Map(), replicaSpec.PathSlice(),
|
||||||
replicaSpec.CreateIfNotPresent, p.addReplicas)
|
replicaSpec.CreateIfNotPresent, p.addReplicas)
|
||||||
@@ -46,6 +53,15 @@ func (p *plugin) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
gvks := make([]string, len(p.FieldSpecs))
|
||||||
|
for i, replicaSpec := range p.FieldSpecs {
|
||||||
|
gvks[i] = replicaSpec.Gvk.String()
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Resource with name %s does not match a config with the following GVK %v",
|
||||||
|
p.Replica.Name, gvks)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,3 +151,85 @@ spec:
|
|||||||
app: app
|
app: app
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatchesCurrentID(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin("builtin", "", "PrefixSuffixTransformer")
|
||||||
|
tc.BuildGoPlugin("builtin", "", "ReplicaCountTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PrefixSuffixTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
suffix: -test
|
||||||
|
fieldSpecs:
|
||||||
|
- path: metadata/name
|
||||||
|
`, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deployment`)
|
||||||
|
|
||||||
|
rm, _ = th.RunTransformerFromResMap(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ReplicaCountTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
|
||||||
|
replica:
|
||||||
|
name: deployment-test
|
||||||
|
count: 23
|
||||||
|
fieldSpecs:
|
||||||
|
- path: spec/replicas
|
||||||
|
create: true
|
||||||
|
kind: Deployment`, rm)
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deployment-test
|
||||||
|
spec:
|
||||||
|
replicas: 23
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoMatch(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin("builtin", "", "ReplicaCountTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
err := th.ErrorFromLoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ReplicaCountTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
replica:
|
||||||
|
name: service
|
||||||
|
count: 3
|
||||||
|
fieldSpecs:
|
||||||
|
- path: spec/replicas
|
||||||
|
create: true
|
||||||
|
kind: Deployment
|
||||||
|
`, `
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: service
|
||||||
|
spec:
|
||||||
|
`)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("No match should return an error")
|
||||||
|
}
|
||||||
|
if err.Error() !=
|
||||||
|
"Resource with name service does not match a config with the following GVK [~G_~V_Deployment]" {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user