mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-21 05:48:18 +00:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58492e2d83 | ||
|
|
a9f44aa259 | ||
|
|
b17d7fbbfd | ||
|
|
d78e77fb92 | ||
|
|
64fdb8d760 | ||
|
|
a377ec1dde | ||
|
|
87e9964091 | ||
|
|
60d8334fed | ||
|
|
71f5105a86 | ||
|
|
09a62efe88 | ||
|
|
6dbf4b5b60 | ||
|
|
5401bd367b | ||
|
|
f7def79764 | ||
|
|
cda909a609 | ||
|
|
6f61cadf9f | ||
|
|
1c616b1962 | ||
|
|
849343fb41 | ||
|
|
8810027d89 | ||
|
|
548ea8a9fb | ||
|
|
81b5cf65d6 | ||
|
|
dc9ae64646 | ||
|
|
829cb2baa3 | ||
|
|
7b301446fa | ||
|
|
4a297fa138 | ||
|
|
7811d9f2bc | ||
|
|
21ff81b758 | ||
|
|
485bbddd3e | ||
|
|
6dc80293a6 | ||
|
|
b649ad5c69 | ||
|
|
d782abb214 | ||
|
|
95f5becee1 | ||
|
|
694d809f33 | ||
|
|
df3c3c3357 | ||
|
|
99e770b05a | ||
|
|
340cb2b385 | ||
|
|
cdbd83a645 | ||
|
|
fab2a5a5d7 | ||
|
|
8da2f37181 | ||
|
|
c906a0c16e | ||
|
|
93618166b6 | ||
|
|
babfb3faa9 | ||
|
|
cedf215445 | ||
|
|
51a4907f89 | ||
|
|
6457162383 | ||
|
|
7f0e9e3a6a | ||
|
|
95cf508b2b | ||
|
|
4a565ffdb8 | ||
|
|
17f1779a48 | ||
|
|
a76cb0b008 | ||
|
|
9700bc3298 | ||
|
|
ce31dac24f | ||
|
|
a81b2e32e0 | ||
|
|
b713d5a1cc | ||
|
|
e11ba17248 | ||
|
|
3d9d4bd36f | ||
|
|
6a3e3c3a71 |
@@ -3,12 +3,11 @@ language: go
|
||||
go:
|
||||
- 1.10.x
|
||||
|
||||
# go_import_path: k8s.io/kubectl
|
||||
go_import_path: sigs.k8s.io/kustomize
|
||||
|
||||
before_install:
|
||||
- source ./bin/consider-early-travis-exit.sh
|
||||
- sudo apt-get install tree
|
||||
- go get -u github.com/opennota/check/cmd/varcheck
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u golang.org/x/tools/cmd/goimports
|
||||
- go get -u github.com/onsi/ginkgo/ginkgo
|
||||
|
||||
18
Gopkg.lock
generated
18
Gopkg.lock
generated
@@ -251,6 +251,14 @@
|
||||
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
|
||||
version = "1.1.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:10e1dfc240bcd0fce14366215fd2b070e79d9b9460b27382db4423ad74204f2b"
|
||||
name = "github.com/krishicks/yaml-patch"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "83cc9ac50becbbfafb86a89167f3bc5372e8e530"
|
||||
version = "v0.0.10"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d9e483f4b9e306facf126bd90b02d512bd22ea4471e1568867e32221a8abbb16"
|
||||
@@ -427,9 +435,14 @@
|
||||
digest = "1:bcb2285bb525712de7903a5d254c2789df65c8b58d2cfac5a26d950ad94c2079"
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/equality",
|
||||
"pkg/api/meta",
|
||||
"pkg/api/resource",
|
||||
"pkg/api/validation",
|
||||
"pkg/apis/meta/v1",
|
||||
"pkg/apis/meta/v1/unstructured",
|
||||
"pkg/apis/meta/v1/validation",
|
||||
"pkg/apis/meta/v1beta1",
|
||||
"pkg/conversion",
|
||||
"pkg/conversion/queryparams",
|
||||
"pkg/fields",
|
||||
@@ -490,17 +503,22 @@
|
||||
"github.com/ghodss/yaml",
|
||||
"github.com/golang/glog",
|
||||
"github.com/hashicorp/go-getter",
|
||||
"github.com/krishicks/yaml-patch",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/spf13/cobra",
|
||||
"gopkg.in/yaml.v2",
|
||||
"k8s.io/api/core/v1",
|
||||
"k8s.io/apimachinery/pkg/api/validation",
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/validation",
|
||||
"k8s.io/apimachinery/pkg/runtime",
|
||||
"k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"k8s.io/apimachinery/pkg/util/mergepatch",
|
||||
"k8s.io/apimachinery/pkg/util/sets",
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch",
|
||||
"k8s.io/apimachinery/pkg/util/validation",
|
||||
"k8s.io/apimachinery/pkg/util/validation/field",
|
||||
"k8s.io/apimachinery/pkg/util/yaml",
|
||||
"k8s.io/client-go/kubernetes/scheme",
|
||||
"k8s.io/kube-openapi/pkg/common",
|
||||
|
||||
@@ -60,3 +60,7 @@
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-getter"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/krishicks/yaml-patch"
|
||||
version = "0.0.10"
|
||||
|
||||
@@ -23,10 +23,10 @@ set -x
|
||||
# - Use /go as the default GOPATH because this is what the image uses
|
||||
# - Link our current directory (containing the source code) to the package location in the GOPATH
|
||||
|
||||
OWNER="kubernetes-sigs"
|
||||
OWNER="sigs.k8s.io"
|
||||
REPO="kustomize"
|
||||
|
||||
GO_PKG_OWNER=$GOPATH/src/github.com/$OWNER
|
||||
GO_PKG_OWNER=$GOPATH/src/$OWNER
|
||||
GO_PKG_PATH=$GO_PKG_OWNER/$REPO
|
||||
|
||||
mkdir -p $GO_PKG_OWNER
|
||||
|
||||
@@ -4,7 +4,7 @@ project_name: kustomize
|
||||
builds:
|
||||
- main: ./kustomize.go
|
||||
binary: kustomize
|
||||
ldflags: -s -X github.com/kubernetes-sigs/kustomize/pkg/commands.kustomizeVersion={{.Version}} -X github.com/kubernetes-sigs/kustomize/pkg/commands.gitCommit={{.Commit}} -X github.com/kubernetes-sigs/kustomize/pkg/commands.buildDate={{.Date}}
|
||||
ldflags: -s -X sigs.k8s.io/kustomize/pkg/commands.kustomizeVersion={{.Version}} -X sigs.k8s.io/kustomize/pkg/commands.gitCommit={{.Commit}} -X sigs.k8s.io/kustomize/pkg/commands.buildDate={{.Date}}
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
can be considered.
|
||||
1. Submit an issue describing your proposed change to
|
||||
the repo in question.
|
||||
1. The [repo owners](OWNERS) will respond to your issue
|
||||
1. The [repo owners](../OWNERS) will respond to your issue
|
||||
promptly.
|
||||
1. Fork the repo, develop and test your code.
|
||||
See the [github workflow guide].
|
||||
1. For _new features_, provide a markdown-based demo following
|
||||
the pattern established in the [examples](examples) directory.
|
||||
the pattern established in the [examples](../examples) directory.
|
||||
Run `bin/pre-commit.sh` to test your demo.
|
||||
1. Submit a pull request.
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
[DAM]: #declarative-application-management
|
||||
[JSON]: https://www.json.org/
|
||||
[JSONPatch]: https://tools.ietf.org/html/rfc6902
|
||||
[Resource]: #resource
|
||||
[YAML]: http://www.yaml.org/start.html
|
||||
[application]: #application
|
||||
@@ -15,16 +16,19 @@
|
||||
[kubernetes]: #kubernetes
|
||||
[kustomize]: #kustomize
|
||||
[kustomization]: #kustomization
|
||||
[off-the-shelf]: #off-the-shelf
|
||||
[off-the-shelf]: #off-the-shelf-configuration
|
||||
[overlay]: #overlay
|
||||
[overlays]: #overlay
|
||||
[patch]: #patch
|
||||
[patches]: #patch
|
||||
[patchJson6902]: #patchJson6902
|
||||
[patchesJson6902]: #patchjson6902
|
||||
[proposal]: https://github.com/kubernetes/community/pull/1629
|
||||
[rebase]: https://git-scm.com/docs/git-rebase
|
||||
[resource]: #resource
|
||||
[resources]: #resource
|
||||
[rpm]: https://en.wikipedia.org/wiki/Rpm_(software)
|
||||
[strategic merge]: https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
|
||||
[target]: #target
|
||||
[variant]: #variant
|
||||
[variants]: #variant
|
||||
@@ -254,6 +258,15 @@ dependencies. Since any resource file can be used as a
|
||||
patch, one cannot reliably distinguish a resource from
|
||||
a patch just by looking at the file's [YAML].
|
||||
|
||||
## patchJson6902
|
||||
A _patchJson6902_ refers to a kubernetes object and a [JSONPatch]
|
||||
that can patch the object. A [JSONPatch] contains a list of operations to change the object's field directly.
|
||||
This is different from [patch], which is
|
||||
applied to a target kubernetes object by [strategic merge].
|
||||
|
||||
_patchesJson6902_ is a field in kustomization. It contains a list of
|
||||
_patchJson6902_.
|
||||
|
||||
## resource
|
||||
|
||||
A _resource_, in the context of kustomize, is a path to
|
||||
|
||||
@@ -138,6 +138,41 @@ patches:
|
||||
- deployment_increase_replicas.yaml
|
||||
- deployment_increase_memory.yaml
|
||||
|
||||
# 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
|
||||
|
||||
# Each entry in this list should be a relative path to
|
||||
# a file for custom resource definition(CRD).
|
||||
@@ -212,8 +247,12 @@ vars:
|
||||
# image: nginx:1.7.9
|
||||
#```
|
||||
# one can change the tag of myimage to v1 and the tag of nginx to 1.8.0 with the following:
|
||||
#
|
||||
# It also supports digests. If digest is present newTag is ignored.
|
||||
imageTags:
|
||||
- name: mycontainerregistry/myimage
|
||||
newTag: v1
|
||||
- name: nginx
|
||||
newTag: 1.8.0
|
||||
- name: alpine
|
||||
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[OTS]: glossary.md#off-the-shelf
|
||||
[OTS]: glossary.md#off-the-shelf-configuration
|
||||
[apply]: glossary.md#apply
|
||||
[applying]: glossary.md#apply
|
||||
[base]: glossary.md#base
|
||||
[fork]: https://guides.github.com/activities/forking/
|
||||
[variants]: glossary.md#variant
|
||||
[kustomization]: glossary.md#kustomization
|
||||
[off-the-shelf]: glossary.md#off-the-shelf
|
||||
[off-the-shelf]: glossary.md#off-the-shelf-configuration
|
||||
[overlays]: glossary.md#overlay
|
||||
[patch]: glossary.md#patch
|
||||
[patches]: glossary.md#patch
|
||||
|
||||
@@ -7,7 +7,7 @@ tests, and should work with HEAD
|
||||
|
||||
<!-- @installkustomize @test -->
|
||||
```
|
||||
go get github.com/kubernetes-sigs/kustomize
|
||||
go get sigs.k8s.io/kustomize
|
||||
```
|
||||
|
||||
* [hello world](helloWorld/README.md) - Deploy multiple
|
||||
@@ -40,3 +40,5 @@ go get github.com/kubernetes-sigs/kustomize
|
||||
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
|
||||
|
||||
* [remote target](remoteBuild.md) - Building a kustomization from a github URL
|
||||
|
||||
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
|
||||
|
||||
@@ -73,7 +73,7 @@ commonLabels:
|
||||
who: alice
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- temperature.yaml
|
||||
EOF
|
||||
|
||||
@@ -96,7 +96,7 @@ commonLabels:
|
||||
who: bob
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- topping.yaml
|
||||
EOF
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[patch]: ../../docs/glossary.md#patch
|
||||
[resource]: ../../docs/glossary.md#resource
|
||||
[variant]: ../../docs/glossary.md#variant
|
||||
[patch]: ../docs/glossary.md#patch
|
||||
[resource]: ../docs/glossary.md#resource
|
||||
[variant]: ../docs/glossary.md#variant
|
||||
|
||||
## ConfigMap generation and rolling updates
|
||||
|
||||
@@ -67,7 +67,7 @@ commonAnnotations:
|
||||
note: Hello, I am staging!
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- map.yaml
|
||||
EOF
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ commonAnnotations:
|
||||
note: Hello, I am staging!
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- map.yaml
|
||||
EOF
|
||||
```
|
||||
@@ -197,7 +197,7 @@ commonAnnotations:
|
||||
note: Hello, I am production!
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment.yaml
|
||||
EOF
|
||||
```
|
||||
|
||||
77
examples/jsonpatch.md
Normal file
77
examples/jsonpatch.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Demo: applying a json patch
|
||||
|
||||
A kustomization file supports customizing resources via [JSON patches](https://tools.ietf.org/html/rfc6902).
|
||||
|
||||
The example below modifies an `Ingress` object with such a patch.
|
||||
|
||||
Make a `kustomization` containing an ingress resource.
|
||||
|
||||
<!-- @createIngress @test -->
|
||||
```
|
||||
DEMO_HOME=$(mktemp -d)
|
||||
|
||||
cat <<EOF >$DEMO_HOME/kustomization.yaml
|
||||
resources:
|
||||
- ingress.yaml
|
||||
EOF
|
||||
|
||||
cat <<EOF >$DEMO_HOME/ingress.yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: my-ingress
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: my-api
|
||||
servicePort: 80
|
||||
EOF
|
||||
```
|
||||
|
||||
Declare a JSON patch file to update two fields of the Ingress object:
|
||||
|
||||
- change host from `foo.bar.com` to `foo.bar.io`
|
||||
- change servicePort from `80` to `8080`
|
||||
|
||||
<!-- @addJsonPatch @test -->
|
||||
```
|
||||
cat <<EOF >$DEMO_HOME/ingress_patch.json
|
||||
[
|
||||
{"op": "replace", "path": "/spec/rules/0/host", "value": "foo.bar.io"},
|
||||
{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/servicePort", "value": 8080}
|
||||
]
|
||||
EOF
|
||||
```
|
||||
|
||||
Apply the patch by adding _patchesJson6902_ field in kustomization.yaml
|
||||
|
||||
<!-- @applyJsonPatch @test -->
|
||||
```
|
||||
cat <<EOF >>$DEMO_HOME/kustomization.yaml
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: extensions
|
||||
version: v1beta1
|
||||
kind: Ingress
|
||||
name: my-ingress
|
||||
path: ingress_patch.json
|
||||
EOF
|
||||
```
|
||||
|
||||
Running `kustomize build $DEMO_HOME`, in the ourput confirm that host has been updated correctly.
|
||||
<!-- @confirmHost @test -->
|
||||
```
|
||||
test 1 == \
|
||||
$(kustomize build $DEMO_HOME | grep "host: foo.bar.io" | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
Running `kustomize build $DEMO_HOME`, in the ourput confirm that the servicePort has been updated correctly.
|
||||
<!-- @confirmServicePort @test -->
|
||||
```
|
||||
test 1 == \
|
||||
$(kustomize build $DEMO_HOME | grep "servicePort: 8080" | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment.yaml
|
||||
namePrefix: production-
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment.yaml
|
||||
nameprefix: staging-
|
||||
configMapGenerator:
|
||||
|
||||
@@ -107,7 +107,7 @@ Now the workspace has following directories
|
||||
> └── kustomization.yaml
|
||||
> ```
|
||||
|
||||
Confirm that the `kustomize build` output contains three pod objects from dev, staing and production variants.
|
||||
Confirm that the `kustomize build` output contains three pod objects from dev, staging and production variants.
|
||||
|
||||
<!-- @confirmVariants @test -->
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ Off the shelf MySQL uses `emptyDir` type volume, which
|
||||
gets wiped away if the MySQL Pod is recreated, and that
|
||||
is certainly not desirable for production
|
||||
environment. So we want to use Persistent Disk in
|
||||
production. kustomize lets you apply `patches` to the
|
||||
production. kustomize lets you apply `patchesStrategicMerge` to the
|
||||
resources.
|
||||
|
||||
<!-- @createPatchFile @test -->
|
||||
@@ -176,7 +176,7 @@ Add the patch file to `kustomization.yaml`:
|
||||
<!-- @specifyPatch @test -->
|
||||
```
|
||||
cat <<'EOF' >> $DEMO_HOME/kustomization.yaml
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- persistent-disk.yaml
|
||||
EOF
|
||||
```
|
||||
@@ -188,7 +188,7 @@ Lets break this down:
|
||||
in deployment.yaml
|
||||
|
||||
- Then we added `persistent-disk.yaml` to list of
|
||||
`patches` in `kustomization.yaml`. `kustomize build`
|
||||
`patchesStrategicMerge` in `kustomization.yaml`. `kustomize build`
|
||||
will apply this patch to the deployment resource with
|
||||
the name `mysql` as defined in the patch.
|
||||
|
||||
|
||||
@@ -16,6 +16,17 @@ test 3 == \
|
||||
echo $?
|
||||
```
|
||||
|
||||
Overlays can be remote as well:
|
||||
|
||||
<!-- @remoteOverlayBuild @test -->
|
||||
|
||||
```
|
||||
target=github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?ref=v1.0.6
|
||||
test 1 == \
|
||||
$(kustomize build $target | grep cluster-a-dev-myapp-pod | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
|
||||
A base can also be specified as a URL:
|
||||
|
||||
<!-- @createOverlay @test -->
|
||||
@@ -55,4 +66,4 @@ Here are some example urls pointing to Github repos following this convention.
|
||||
`github.com/Liujingfang1/kustomize//examples/helloWorld?ref=repoUrl2`
|
||||
- a subdirectory in a repo on commit `7050a45134e9848fca214ad7e7007e96e5042c03`
|
||||
|
||||
`github.com/Liujingfang1/kustomize//examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03`
|
||||
`github.com/Liujingfang1/kustomize//examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03`
|
||||
|
||||
@@ -291,7 +291,7 @@ kustomize edit add patch healthcheck_patch.yaml
|
||||
`kustomization.yaml` should have patches field:
|
||||
|
||||
> ```
|
||||
> patches:
|
||||
> patchesStrategicMerge:
|
||||
> - patch.yaml
|
||||
> - memorylimit_patch.yaml
|
||||
> - healthcheck_patch.yaml
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
bases:
|
||||
- ../../base
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- patch.yaml
|
||||
- healthcheck_patch.yaml
|
||||
- memorylimit_patch.yaml
|
||||
|
||||
@@ -53,7 +53,7 @@ bases:
|
||||
- wordpress
|
||||
- mysql
|
||||
namePrefix: demo-
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- patch.yaml
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
bases:
|
||||
- wordpress
|
||||
- mysql
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- patch.yaml
|
||||
namePrefix: demo-
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/commands"
|
||||
"sigs.k8s.io/kustomize/pkg/commands"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -26,17 +26,19 @@ import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/crds"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
interror "github.com/kubernetes-sigs/kustomize/pkg/internal/error"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resource"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/transformers"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/pkg/configmapandsecret"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/crds"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
interror "sigs.k8s.io/kustomize/pkg/internal/error"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/patch"
|
||||
patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
// Application implements the guts of the kustomize 'build' command.
|
||||
@@ -61,7 +63,6 @@ func NewApplication(ldr loader.Loader, fSys fs.FileSystem) (*Application, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Application{kustomization: &m, ldr: ldr, fSys: fSys}, nil
|
||||
}
|
||||
|
||||
@@ -150,7 +151,8 @@ func (a *Application) loadCustomizedResMap() (resmap.ResMap, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
patches, err := resmap.NewResourceSliceFromPatches(a.ldr, a.kustomization.Patches)
|
||||
a.kustomization.PatchesStrategicMerge = patch.Append(a.kustomization.PatchesStrategicMerge, a.kustomization.Patches...)
|
||||
patches, err := resmap.NewResourceSliceFromPatches(a.ldr, a.kustomization.PatchesStrategicMerge)
|
||||
if err != nil {
|
||||
errs.Append(errors.Wrap(err, "NewResourceSliceFromPatches"))
|
||||
}
|
||||
@@ -165,6 +167,11 @@ func (a *Application) loadCustomizedResMap() (resmap.ResMap, error) {
|
||||
return nil, err
|
||||
}
|
||||
r = append(r, t)
|
||||
t, err = patchtransformer.NewPatchJson6902Factory(a.ldr).MakePatchJson6902Transformer(a.kustomization.PatchesJson6902)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = append(r, t)
|
||||
t, err = transformers.NewImageTagTransformer(a.kustomization.ImageTags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -22,14 +22,14 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/internal/loadertest"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resource"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -54,6 +54,13 @@ secretGenerator:
|
||||
DB_USERNAME: "printf admin"
|
||||
DB_PASSWORD: "printf somepw"
|
||||
type: Opaque
|
||||
patchesJson6902:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: dply1
|
||||
path: jsonpatch.json
|
||||
`
|
||||
kustomizationContent2 = `
|
||||
secretGenerator:
|
||||
@@ -73,6 +80,9 @@ kind: Namespace
|
||||
metadata:
|
||||
name: ns1
|
||||
`
|
||||
jsonpatchContent = `[
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
||||
]`
|
||||
)
|
||||
|
||||
func makeLoader1(t *testing.T) loader.Loader {
|
||||
@@ -89,6 +99,10 @@ func makeLoader1(t *testing.T) loader.Loader {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
err = ldr.AddFile("/testpath/jsonpatch.json", []byte(jsonpatchContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
return ldr
|
||||
}
|
||||
|
||||
@@ -114,6 +128,7 @@ func TestResources1(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replica": "3",
|
||||
"selector": map[string]interface{}{
|
||||
"matchLabels": map[string]interface{}{
|
||||
"app": "nginx",
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
type addBaseOptions struct {
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -20,21 +20,22 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/validate"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/validators"
|
||||
)
|
||||
|
||||
// KindOfAdd is the kind of metadata being added: label or annotation
|
||||
type KindOfAdd int
|
||||
// kindOfAdd is the kind of metadata being added: label or annotation
|
||||
type kindOfAdd int
|
||||
|
||||
const (
|
||||
annotation KindOfAdd = iota
|
||||
annotation kindOfAdd = iota
|
||||
label
|
||||
)
|
||||
|
||||
func (k KindOfAdd) String() string {
|
||||
func (k kindOfAdd) String() string {
|
||||
kinds := [...]string{
|
||||
"annotation",
|
||||
"label",
|
||||
@@ -46,127 +47,129 @@ func (k KindOfAdd) String() string {
|
||||
}
|
||||
|
||||
type addMetadataOptions struct {
|
||||
metadata map[string]string
|
||||
metadata map[string]string
|
||||
mapValidator validators.MapValidatorFunc
|
||||
kind kindOfAdd
|
||||
}
|
||||
|
||||
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
|
||||
func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
|
||||
func newCmdAddAnnotation(fSys fs.FileSystem, v validators.MapValidatorFunc) *cobra.Command {
|
||||
var o addMetadataOptions
|
||||
|
||||
o.kind = annotation
|
||||
o.mapValidator = v
|
||||
cmd := &cobra.Command{
|
||||
Use: "annotation",
|
||||
Short: "Adds one or more commonAnnotations to the kustomization.yaml in current directory",
|
||||
Short: "Adds one or more commonAnnotations to " + constants.KustomizationFileName,
|
||||
Example: `
|
||||
add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.ValidateAndParse(args, annotation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunAddAnnotation(fsys, annotation)
|
||||
return o.runE(args, fSys, o.addAnnotations)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// newCmdAddLabel adds one or more commonLabels to the kustomization file.
|
||||
func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
|
||||
func newCmdAddLabel(fSys fs.FileSystem, v validators.MapValidatorFunc) *cobra.Command {
|
||||
var o addMetadataOptions
|
||||
|
||||
o.kind = label
|
||||
o.mapValidator = v
|
||||
cmd := &cobra.Command{
|
||||
Use: "label",
|
||||
Short: "Adds one or more commonLabels to the kustomization.yaml in current directory",
|
||||
Short: "Adds one or more commonLabels to " + constants.KustomizationFileName,
|
||||
Example: `
|
||||
add label {labelKey1:labelValue1},{labelKey2:labelValue2}`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.ValidateAndParse(args, label)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunAddLabel(fsys, label)
|
||||
return o.runE(args, fSys, o.addLabels)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ValidateAndParse validates addLabel and addAnnotation commands and parses them into o.metadata
|
||||
func (o *addMetadataOptions) ValidateAndParse(args []string, k KindOfAdd) error {
|
||||
o.metadata = make(map[string]string)
|
||||
func (o *addMetadataOptions) runE(
|
||||
args []string, fSys fs.FileSystem, adder func(*types.Kustomization) error) error {
|
||||
err := o.validateAndParse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kf, err := newKustomizationFile(constants.KustomizationFileName, fSys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := kf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adder(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return kf.write(m)
|
||||
}
|
||||
|
||||
// validateAndParse validates `add` commands and parses them into o.metadata
|
||||
func (o *addMetadataOptions) validateAndParse(args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify %s", k)
|
||||
return fmt.Errorf("must specify %s", o.kind)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("%ss must be comma-separated, with no spaces. See help text for example", k)
|
||||
return fmt.Errorf("%ss must be comma-separated, with no spaces", o.kind)
|
||||
}
|
||||
inputs := strings.Split(args[0], ",")
|
||||
m, err := o.convertToMap(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = o.mapValidator(m); err != nil {
|
||||
return err
|
||||
}
|
||||
o.metadata = m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *addMetadataOptions) convertToMap(arg string) (map[string]string, error) {
|
||||
result := make(map[string]string)
|
||||
inputs := strings.Split(arg, ",")
|
||||
for _, input := range inputs {
|
||||
switch k {
|
||||
case label:
|
||||
valid, err := validate.IsValidLabel(input)
|
||||
if !valid {
|
||||
return err
|
||||
}
|
||||
case annotation:
|
||||
valid, err := validate.IsValidAnnotation(input)
|
||||
if !valid {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown metadata kind %s", k)
|
||||
}
|
||||
//parse annotation keys and values into metadata
|
||||
kv := strings.Split(input, ":")
|
||||
o.metadata[kv[0]] = kv[1]
|
||||
if len(kv[0]) < 1 {
|
||||
return nil, o.makeError(input, "empty key")
|
||||
}
|
||||
if len(kv) > 2 {
|
||||
return nil, o.makeError(input, "too many colons")
|
||||
}
|
||||
if len(kv) > 1 {
|
||||
result[kv[0]] = kv[1]
|
||||
} else {
|
||||
result[kv[0]] = ""
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *addMetadataOptions) addAnnotations(m *types.Kustomization) error {
|
||||
if m.CommonAnnotations == nil {
|
||||
m.CommonAnnotations = make(map[string]string)
|
||||
}
|
||||
return o.writeToMap(m.CommonAnnotations, annotation)
|
||||
}
|
||||
|
||||
func (o *addMetadataOptions) addLabels(m *types.Kustomization) error {
|
||||
if m.CommonLabels == nil {
|
||||
m.CommonLabels = make(map[string]string)
|
||||
}
|
||||
return o.writeToMap(m.CommonLabels, label)
|
||||
}
|
||||
|
||||
func (o *addMetadataOptions) writeToMap(m map[string]string, kind kindOfAdd) error {
|
||||
for k, v := range o.metadata {
|
||||
if _, ok := m[k]; ok {
|
||||
return fmt.Errorf("%s %s already in kustomization file", kind, k)
|
||||
}
|
||||
m[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunAddAnnotation runs addAnnotation command, doing the real work.
|
||||
func (o *addMetadataOptions) RunAddAnnotation(fsys fs.FileSystem, k KindOfAdd) error {
|
||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.CommonAnnotations == nil {
|
||||
m.CommonAnnotations = make(map[string]string)
|
||||
}
|
||||
|
||||
for key, value := range o.metadata {
|
||||
if k == annotation {
|
||||
if _, ok := m.CommonAnnotations[key]; ok {
|
||||
return fmt.Errorf("%s %s already in kustomization file", k, key)
|
||||
}
|
||||
m.CommonAnnotations[key] = value
|
||||
}
|
||||
}
|
||||
return mf.write(m)
|
||||
}
|
||||
|
||||
// RunAddLabel runs addLabel command, doing the real work.
|
||||
func (o *addMetadataOptions) RunAddLabel(fsys fs.FileSystem, k KindOfAdd) error {
|
||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.CommonLabels == nil {
|
||||
m.CommonLabels = make(map[string]string)
|
||||
}
|
||||
|
||||
for key, value := range o.metadata {
|
||||
if _, ok := m.CommonLabels[key]; ok {
|
||||
return fmt.Errorf("%s %s already in kustomization file", k, key)
|
||||
}
|
||||
m.CommonLabels[key] = value
|
||||
}
|
||||
return mf.write(m)
|
||||
func (o *addMetadataOptions) makeError(input string, message string) error {
|
||||
return fmt.Errorf("invalid %s: %s (%s)", o.kind, input, message)
|
||||
}
|
||||
|
||||
@@ -17,98 +17,45 @@ limitations under the License.
|
||||
package commands
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/validators"
|
||||
)
|
||||
|
||||
func TestParseValidateInput(t *testing.T) {
|
||||
var testcases = []struct {
|
||||
input string
|
||||
valid bool
|
||||
name string
|
||||
expectedData map[string]string
|
||||
kind KindOfAdd
|
||||
}{
|
||||
{
|
||||
input: "otters:cute",
|
||||
valid: true,
|
||||
name: "Adds single input",
|
||||
expectedData: map[string]string{
|
||||
"otters": "cute",
|
||||
},
|
||||
kind: label,
|
||||
},
|
||||
{
|
||||
input: "owls:great,unicorns:magical",
|
||||
valid: true,
|
||||
name: "Adds two items",
|
||||
expectedData: map[string]string{
|
||||
"owls": "great",
|
||||
"unicorns": "magical",
|
||||
},
|
||||
kind: label,
|
||||
},
|
||||
{
|
||||
input: "123:45",
|
||||
valid: true,
|
||||
name: "Numeric input is allowed",
|
||||
expectedData: map[string]string{
|
||||
"123": "45",
|
||||
},
|
||||
kind: annotation,
|
||||
},
|
||||
{
|
||||
input: " ",
|
||||
valid: false,
|
||||
name: "Empty space input",
|
||||
expectedData: nil,
|
||||
kind: annotation,
|
||||
},
|
||||
func makeKustomization(t *testing.T) *types.Kustomization {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
kf, err := newKustomizationFile(constants.KustomizationFileName, fakeFS)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected new error %v", err)
|
||||
}
|
||||
var o addMetadataOptions
|
||||
for _, tc := range testcases {
|
||||
args := []string{tc.input}
|
||||
err := o.ValidateAndParse(args, tc.kind)
|
||||
if err != nil && tc.valid {
|
||||
t.Errorf("for test case %s, unexpected cmd error: %v", tc.name, err)
|
||||
}
|
||||
if err == nil && !tc.valid {
|
||||
t.Errorf("unexpected error: expected invalid format error for test case %v", tc.name)
|
||||
}
|
||||
//o.metadata should be the same as expectedData
|
||||
if tc.valid {
|
||||
if !reflect.DeepEqual(o.metadata, tc.expectedData) {
|
||||
t.Errorf("unexpected error: for test case %s, unexpected data was added", tc.name)
|
||||
}
|
||||
} else {
|
||||
if len(o.metadata) != 0 {
|
||||
t.Errorf("unexpected error: for test case %s, expected no data to be added", tc.name)
|
||||
}
|
||||
}
|
||||
m, err := kf.read()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected read error %v", err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func TestRunAddAnnotation(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
var o addMetadataOptions
|
||||
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
|
||||
|
||||
err := o.RunAddAnnotation(fakeFS, annotation)
|
||||
m := makeKustomization(t)
|
||||
err := o.addAnnotations(m)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
// adding the same test input should not work
|
||||
err = o.RunAddAnnotation(fakeFS, annotation)
|
||||
err = o.addAnnotations(m)
|
||||
if err == nil {
|
||||
t.Errorf("expected already in kustomization file error")
|
||||
}
|
||||
// adding new annotations should work
|
||||
o.metadata = map[string]string{"new": "annotation"}
|
||||
err = o.RunAddAnnotation(fakeFS, annotation)
|
||||
err = o.addAnnotations(m)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
@@ -116,47 +63,122 @@ func TestRunAddAnnotation(t *testing.T) {
|
||||
|
||||
func TestAddAnnotationNoArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
cmd := newCmdAddAnnotation(fakeFS)
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
err := cmd.Execute()
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is %v", err)
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err != nil && err.Error() != "must specify annotation" {
|
||||
if err.Error() != "must specify annotation" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationInvalidFormat(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeSadMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{"whatever:whatever"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != validators.SAD {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationManyArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{"k1:v1,k2:v2,k3:v3,k4:v5"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyCall()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationNoKey(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{":nokey"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != "invalid annotation: :nokey (empty key)" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationTooManyColons(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{"key:v1:v2"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != "invalid annotation: key:v1:v2 (too many colons)" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationNoValue(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{"no:,value"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyCall()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationMultipleArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
cmd := newCmdAddAnnotation(fakeFS)
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddAnnotation(fakeFS, v.Validator)
|
||||
args := []string{"this:annotation", "has:spaces"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is %v", err)
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err != nil && err.Error() != "annotations must be comma-separated, with no spaces. See help text for example" {
|
||||
if err.Error() != "annotations must be comma-separated, with no spaces" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAddLabel(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
var o addMetadataOptions
|
||||
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
|
||||
|
||||
err := o.RunAddLabel(fakeFS, label)
|
||||
m := makeKustomization(t)
|
||||
err := o.addLabels(m)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
// adding the same test input should not work
|
||||
err = o.RunAddLabel(fakeFS, label)
|
||||
err = o.addLabels(m)
|
||||
if err == nil {
|
||||
t.Errorf("expected already in kustomization file error")
|
||||
}
|
||||
// adding new labels should work
|
||||
o.metadata = map[string]string{"new": "label"}
|
||||
err = o.RunAddLabel(fakeFS, label)
|
||||
err = o.addLabels(m)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
@@ -164,27 +186,88 @@ func TestRunAddLabel(t *testing.T) {
|
||||
|
||||
func TestAddLabelNoArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
|
||||
cmd := newCmdAddLabel(fakeFS)
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
err := cmd.Execute()
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is: %v", err)
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err != nil && err.Error() != "must specify label" {
|
||||
if err.Error() != "must specify label" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelInvalidFormat(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeSadMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
args := []string{"exclamation!:point"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != validators.SAD {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelNoKey(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
args := []string{":nokey"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != "invalid label: :nokey (empty key)" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelTooManyColons(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
args := []string{"key:v1:v2"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err.Error() != "invalid label: key:v1:v2 (too many colons)" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelNoValue(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
args := []string{"no,value:"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyCall()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelMultipleArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
cmd := newCmdAddLabel(fakeFS)
|
||||
v := validators.MakeHappyMapValidator(t)
|
||||
cmd := newCmdAddLabel(fakeFS, v.Validator)
|
||||
args := []string{"this:input", "has:spaces"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
v.VerifyNoCall()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is: %v", err)
|
||||
t.Errorf("expected an error")
|
||||
}
|
||||
if err != nil && err.Error() != "labels must be comma-separated, with no spaces. See help text for example" {
|
||||
if err.Error() != "labels must be comma-separated, with no spaces" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,9 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/patch"
|
||||
)
|
||||
|
||||
type addPatchOptions struct {
|
||||
@@ -88,12 +89,12 @@ func (o *addPatchOptions) RunAddPatch(fsys fs.FileSystem) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, patch := range patches {
|
||||
if stringInSlice(patch, m.Patches) {
|
||||
log.Printf("patch %s already in kustomization file", patch)
|
||||
for _, p := range patches {
|
||||
if patch.Exist(m.PatchesStrategicMerge, p) || stringInSlice(p, m.Patches) {
|
||||
log.Printf("patch %s already in kustomization file", p)
|
||||
continue
|
||||
}
|
||||
m.Patches = append(m.Patches, patch)
|
||||
m.PatchesStrategicMerge = patch.Append(m.PatchesStrategicMerge, p)
|
||||
}
|
||||
|
||||
return mf.write(m)
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
type addResourceOptions struct {
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/app"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/app"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
)
|
||||
|
||||
type buildOptions struct {
|
||||
@@ -44,7 +44,7 @@ The url should follow hashicorp/go-getter URL format described in
|
||||
https://github.com/hashicorp/go-getter#url-format
|
||||
|
||||
url examples:
|
||||
github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6
|
||||
sigs.k8s.io/kustomize//examples/multibases?ref=v1.0.6
|
||||
github.com/Liujingfang1/mysql
|
||||
github.com/Liujingfang1/kustomize//examples/helloWorld?ref=repoUrl2
|
||||
`
|
||||
|
||||
@@ -27,9 +27,9 @@ import (
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
type buildTestCase struct {
|
||||
|
||||
@@ -19,7 +19,7 @@ package commands
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
// cMapFlagsAndArgs encapsulates the options for add configmap commands.
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
func TestDataConfigValidation_NoName(t *testing.T) {
|
||||
|
||||
@@ -21,8 +21,9 @@ import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/validators"
|
||||
)
|
||||
|
||||
// NewDefaultCommand returns the default (aka root) command for kustomize command.
|
||||
@@ -36,7 +37,7 @@ func NewDefaultCommand() *cobra.Command {
|
||||
Long: `
|
||||
kustomize manages declarative configuration of Kubernetes.
|
||||
|
||||
See https://github.com/kubernetes-sigs/kustomize
|
||||
See https://sigs.k8s.io/kustomize
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -109,8 +110,8 @@ func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
|
||||
newCmdAddPatch(fsys),
|
||||
newCmdAddConfigMap(fsys),
|
||||
newCmdAddBase(fsys),
|
||||
newCmdAddLabel(fsys),
|
||||
newCmdAddAnnotation(fsys),
|
||||
newCmdAddLabel(fsys, validators.MakeLabelValidator()),
|
||||
newCmdAddAnnotation(fsys, validators.MakeAnnotationValidator()),
|
||||
)
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/configmapandsecret"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
func newCmdAddConfigMap(fSys fs.FileSystem) *cobra.Command {
|
||||
|
||||
@@ -19,8 +19,8 @@ package commands
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
func TestNewAddConfigMapIsNotNil(t *testing.T) {
|
||||
|
||||
@@ -28,10 +28,9 @@ import (
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
interror "github.com/kubernetes-sigs/kustomize/pkg/internal/error"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -47,6 +46,8 @@ var (
|
||||
"CommonLabels",
|
||||
"CommonAnnotations",
|
||||
"Patches",
|
||||
"PatchesStrategicMerge",
|
||||
"PatchesJson6902",
|
||||
"ConfigMapGenerator",
|
||||
"SecretGenerator",
|
||||
"Vars",
|
||||
@@ -87,22 +88,17 @@ func newKustomizationFile(mPath string, fsys fs.FileSystem) (*kustomizationFile,
|
||||
|
||||
func (mf *kustomizationFile) validate() error {
|
||||
if !mf.fsys.Exists(mf.path) {
|
||||
errorMsg := fmt.Sprintf("Missing kustomization file '%s'.\n", mf.path)
|
||||
merr := interror.KustomizationError{KustomizationPath: mf.path, ErrorMsg: errorMsg}
|
||||
return merr
|
||||
return fmt.Errorf("Missing kustomization file '%s'.\n", mf.path)
|
||||
}
|
||||
if mf.fsys.IsDir(mf.path) {
|
||||
mf.path = path.Join(mf.path, constants.KustomizationFileName)
|
||||
if !mf.fsys.Exists(mf.path) {
|
||||
errorMsg := fmt.Sprintf("Missing kustomization file '%s'.\n", mf.path)
|
||||
merr := interror.KustomizationError{KustomizationPath: mf.path, ErrorMsg: errorMsg}
|
||||
return merr
|
||||
return fmt.Errorf("Missing kustomization file '%s'.\n", mf.path)
|
||||
}
|
||||
} else {
|
||||
if !strings.HasSuffix(mf.path, constants.KustomizationFileName) {
|
||||
errorMsg := fmt.Sprintf("Kustomization file path (%s) should have %s suffix\n",
|
||||
return fmt.Errorf("Kustomization file path (%s) should have %s suffix\n",
|
||||
mf.path, constants.KustomizationFileSuffix)
|
||||
return interror.KustomizationError{KustomizationPath: mf.path, ErrorMsg: errorMsg}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
func TestWriteAndRead(t *testing.T) {
|
||||
@@ -109,7 +109,7 @@ vars:
|
||||
bases:
|
||||
- ../namespaces
|
||||
# some descriptions for the patches
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- service.yaml
|
||||
- pod.yaml
|
||||
`)
|
||||
@@ -165,7 +165,7 @@ BASES:
|
||||
|
||||
# some descriptions for the patches
|
||||
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- service.yaml
|
||||
- pod.yaml
|
||||
`)
|
||||
@@ -200,7 +200,7 @@ bases:
|
||||
|
||||
# some descriptions for the patches
|
||||
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- service.yaml
|
||||
- pod.yaml
|
||||
`)
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
type setNamePrefixOptions struct {
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -20,16 +20,17 @@ import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
type setImageTagOptions struct {
|
||||
imageTagMap map[string]string
|
||||
imageTagMap map[string]types.ImageTag
|
||||
}
|
||||
|
||||
var pattern = regexp.MustCompile("^(.*):([a-zA-Z0-9._-]*)$")
|
||||
@@ -40,10 +41,10 @@ func newCmdSetImageTag(fsys fs.FileSystem) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "imagetag",
|
||||
Short: "Sets images and their new tags in the kustomization file",
|
||||
Short: "Sets images and their new tags or digests in the kustomization file",
|
||||
Example: `
|
||||
The command
|
||||
set imagetag nginx:1.8.0 my-app:latest
|
||||
set imagetag nginx:1.8.0 my-app:latest alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
|
||||
will add
|
||||
|
||||
imageTags:
|
||||
@@ -51,9 +52,11 @@ imageTags:
|
||||
newTag: 1.8.0
|
||||
- name: my-app
|
||||
newTag: latest
|
||||
- name: alpine
|
||||
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
|
||||
|
||||
to the kustomization file if it doesn't exist,
|
||||
and overwrite the previous newTag if the image name exists.
|
||||
and overwrite the previous ones if the image tag exists.
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.Validate(args)
|
||||
@@ -69,15 +72,28 @@ and overwrite the previous newTag if the image name exists.
|
||||
// Validate validates setImageTag command.
|
||||
func (o *setImageTagOptions) Validate(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("no image and newTag specified")
|
||||
return errors.New("no image specified")
|
||||
}
|
||||
o.imageTagMap = make(map[string]string)
|
||||
|
||||
o.imageTagMap = make(map[string]types.ImageTag)
|
||||
|
||||
for _, arg := range args {
|
||||
imagetag := pattern.FindStringSubmatch(arg)
|
||||
if len(imagetag) != 3 {
|
||||
return errors.New("invalid format of imagetag, must specify it as <image>:<newtag>")
|
||||
if s := strings.Split(arg, "@"); len(s) > 1 {
|
||||
o.imageTagMap[s[0]] = types.ImageTag{
|
||||
Name: s[0],
|
||||
Digest: s[1],
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
s := pattern.FindStringSubmatch(arg)
|
||||
if len(s) != 3 {
|
||||
return errors.New("invalid format of imagetag, must specify it as <image>:<newtag> or <image>@<digest>")
|
||||
}
|
||||
o.imageTagMap[s[1]] = types.ImageTag{
|
||||
Name: s[1],
|
||||
NewTag: s[2],
|
||||
}
|
||||
o.imageTagMap[imagetag[1]] = imagetag[2]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -92,16 +108,18 @@ func (o *setImageTagOptions) RunSetImageTags(fsys fs.FileSystem) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageTagMap := map[string]string{}
|
||||
|
||||
for _, it := range m.ImageTags {
|
||||
imageTagMap[it.Name] = it.NewTag
|
||||
}
|
||||
for key, value := range o.imageTagMap {
|
||||
imageTagMap[key] = value
|
||||
if _, ok := o.imageTagMap[it.Name]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
o.imageTagMap[it.Name] = it
|
||||
}
|
||||
|
||||
var imageTags []types.ImageTag
|
||||
for key, value := range imageTagMap {
|
||||
imageTags = append(imageTags, types.ImageTag{Name: key, NewTag: value})
|
||||
for _, v := range o.imageTagMap {
|
||||
imageTags = append(imageTags, v)
|
||||
}
|
||||
sort.Slice(imageTags, func(i, j int) bool {
|
||||
return imageTags[i].Name < imageTags[j].Name
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
func TestSetImageTagsHappyPath(t *testing.T) {
|
||||
@@ -29,7 +29,8 @@ func TestSetImageTagsHappyPath(t *testing.T) {
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
|
||||
cmd := newCmdSetImageTag(fakeFS)
|
||||
args := []string{"image1:tag1", "image2:tag2", "localhost:5000/operator:1.0.0"}
|
||||
args := []string{"image1:tag1", "image2:tag2", "localhost:5000/operator:1.0.0",
|
||||
"foo.bar.baz:5000/one/two@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected cmd error: %v", err)
|
||||
@@ -40,6 +41,8 @@ func TestSetImageTagsHappyPath(t *testing.T) {
|
||||
}
|
||||
expected := []byte(`
|
||||
imageTags:
|
||||
- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
|
||||
name: foo.bar.baz:5000/one/two
|
||||
- name: image1
|
||||
newTag: tag1
|
||||
- name: image2
|
||||
@@ -93,7 +96,7 @@ func TestSetImageTagsNoArgs(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Errorf("expected error: %v", err)
|
||||
}
|
||||
if err.Error() != "no image and newTag specified" {
|
||||
if err.Error() != "no image specified" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
type setNamespaceOptions struct {
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
4
pkg/commands/testdata/testcase-multibases-conflict/base/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-conflict/base/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
resources:
|
||||
- serviceaccount.yaml
|
||||
- rolebinding.yaml
|
||||
namePrefix: base-
|
||||
11
pkg/commands/testdata/testcase-multibases-conflict/base/rolebinding.yaml
vendored
Normal file
11
pkg/commands/testdata/testcase-multibases-conflict/base/rolebinding.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: serviceaccount
|
||||
4
pkg/commands/testdata/testcase-multibases-conflict/base/serviceaccount.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-conflict/base/serviceaccount.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: serviceaccount
|
||||
3
pkg/commands/testdata/testcase-multibases-conflict/combined/kustomization.yaml
vendored
Normal file
3
pkg/commands/testdata/testcase-multibases-conflict/combined/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
bases:
|
||||
- ../overlays/a
|
||||
- ../overlays/b
|
||||
7
pkg/commands/testdata/testcase-multibases-conflict/overlays/a/kustomization.yaml
vendored
Normal file
7
pkg/commands/testdata/testcase-multibases-conflict/overlays/a/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
bases:
|
||||
- ../../base/
|
||||
|
||||
namePrefix: a-
|
||||
|
||||
resources:
|
||||
- serviceaccount.yaml
|
||||
4
pkg/commands/testdata/testcase-multibases-conflict/overlays/a/serviceaccount.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-conflict/overlays/a/serviceaccount.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: serviceaccount
|
||||
4
pkg/commands/testdata/testcase-multibases-conflict/overlays/b/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-conflict/overlays/b/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
bases:
|
||||
- ../../base/
|
||||
|
||||
namePrefix: b-
|
||||
4
pkg/commands/testdata/testcase-multibases-conflict/test.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-conflict/test.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
description: multibases with name reference
|
||||
args: []
|
||||
filename: testdata/testcase-multibases-conflict/combined
|
||||
expectedError: detected conflicts when resolving name references serviceaccount
|
||||
4
pkg/commands/testdata/testcase-multibases-nonconflict/base/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-nonconflict/base/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
resources:
|
||||
- serviceaccount.yaml
|
||||
- rolebinding.yaml
|
||||
namePrefix: base-
|
||||
11
pkg/commands/testdata/testcase-multibases-nonconflict/base/rolebinding.yaml
vendored
Normal file
11
pkg/commands/testdata/testcase-multibases-nonconflict/base/rolebinding.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: serviceaccount
|
||||
4
pkg/commands/testdata/testcase-multibases-nonconflict/base/serviceaccount.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-nonconflict/base/serviceaccount.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: serviceaccount
|
||||
3
pkg/commands/testdata/testcase-multibases-nonconflict/combined/kustomization.yaml
vendored
Normal file
3
pkg/commands/testdata/testcase-multibases-nonconflict/combined/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
bases:
|
||||
- ../overlays/a
|
||||
- ../overlays/b
|
||||
33
pkg/commands/testdata/testcase-multibases-nonconflict/expected.yaml
vendored
Normal file
33
pkg/commands/testdata/testcase-multibases-nonconflict/expected.yaml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: a-base-serviceaccount
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: b-base-serviceaccount
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: a-base-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: a-base-serviceaccount
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: b-base-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: b-base-serviceaccount
|
||||
4
pkg/commands/testdata/testcase-multibases-nonconflict/overlays/a/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-nonconflict/overlays/a/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
bases:
|
||||
- ../../base/
|
||||
|
||||
namePrefix: a-
|
||||
4
pkg/commands/testdata/testcase-multibases-nonconflict/overlays/b/kustomization.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-nonconflict/overlays/b/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
bases:
|
||||
- ../../base/
|
||||
|
||||
namePrefix: b-
|
||||
4
pkg/commands/testdata/testcase-multibases-nonconflict/test.yaml
vendored
Normal file
4
pkg/commands/testdata/testcase-multibases-nonconflict/test.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
description: multibases with name reference
|
||||
args: []
|
||||
filename: testdata/testcase-multibases-nonconflict/combined
|
||||
expectedStdout: testdata/testcase-multibases-nonconflict/expected.yaml
|
||||
@@ -1,7 +1,7 @@
|
||||
namePrefix: staging-
|
||||
commonLabels:
|
||||
env: staging
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment-patch2.yaml
|
||||
- deployment-patch1.yaml
|
||||
bases:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namePrefix: staging-
|
||||
commonLabels:
|
||||
env: staging
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- patches/deployment-patch1.yaml
|
||||
- patches/deployment-patch2.yaml
|
||||
bases:
|
||||
|
||||
@@ -2,7 +2,7 @@ namePrefix: staging-
|
||||
commonLabels:
|
||||
env: staging
|
||||
team: override-foo
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment.yaml
|
||||
bases:
|
||||
- ../package/
|
||||
|
||||
@@ -78,16 +78,10 @@ metadata:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
prometheus.io/path: _status/vars
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/scrape: "true"
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
labels:
|
||||
app: cockroachdb
|
||||
name: dev-base-cockroachdb
|
||||
name: dev-base-cockroachdb-public
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 26257
|
||||
@@ -101,10 +95,16 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
prometheus.io/path: _status/vars
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/scrape: "true"
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
labels:
|
||||
app: cockroachdb
|
||||
name: dev-base-cockroachdb-public
|
||||
name: dev-base-cockroachdb
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: grpc
|
||||
port: 26257
|
||||
|
||||
@@ -19,7 +19,7 @@ package commands
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
func globPatterns(fsys fs.FileSystem, patterns []string) ([]string, error) {
|
||||
|
||||
@@ -23,16 +23,16 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/hash"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/hash"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
// ConfigMapFactory makes ConfigMaps.
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
func makeEnvConfigMap(name string) *corev1.ConfigMap {
|
||||
|
||||
@@ -24,11 +24,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/transformers"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
)
|
||||
|
||||
type pathConfigs struct {
|
||||
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/internal/loadertest"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/transformers"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -7,7 +7,7 @@ commonAnnotations:
|
||||
note: This is a test annotation
|
||||
bases:
|
||||
- ../../package/
|
||||
patches:
|
||||
patchesStrategicMerge:
|
||||
- deployment/deployment.yaml
|
||||
configMapGenerator:
|
||||
- name: app-env
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/exec"
|
||||
"sigs.k8s.io/kustomize/pkg/exec"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
)
|
||||
|
||||
func TestConfigmapError_Error(t *testing.T) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
)
|
||||
|
||||
func TestKustomizationError_Error(t *testing.T) {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
)
|
||||
|
||||
func TestPatchError_Error(t *testing.T) {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
)
|
||||
|
||||
func TestResourceError_Error(t *testing.T) {
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/kustomize/pkg/constants"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -18,13 +18,10 @@ limitations under the License.
|
||||
package loadertest
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
)
|
||||
|
||||
// CleanupCalled indicates if Cleanup is called.
|
||||
var CleanupCalled = false
|
||||
|
||||
// FakeLoader encapsulates the delegate Loader and the fake file system.
|
||||
type FakeLoader struct {
|
||||
fs fs.FileSystem
|
||||
@@ -73,6 +70,5 @@ func (f FakeLoader) Load(location string) ([]byte, error) {
|
||||
|
||||
// Cleanup does nothing
|
||||
func (f FakeLoader) Cleanup() error {
|
||||
CleanupCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const currentDir = "."
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
func TestLoader_Root(t *testing.T) {
|
||||
|
||||
@@ -24,19 +24,22 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-getter"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
// githubLoader loads files from a checkout github repo
|
||||
type githubLoader struct {
|
||||
repo string
|
||||
repo string
|
||||
// target is the directory which is to be built
|
||||
targetDir string
|
||||
// checkoutDir is for the whole repository
|
||||
checkoutDir string
|
||||
loader *fileLoader
|
||||
}
|
||||
|
||||
// Root returns the root location for this Loader.
|
||||
func (l *githubLoader) Root() string {
|
||||
return l.checkoutDir
|
||||
return l.targetDir
|
||||
}
|
||||
|
||||
// New delegates to fileLoader.New
|
||||
@@ -60,15 +63,18 @@ func newGithubLoader(repoUrl string, fs fs.FileSystem) (*githubLoader, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target := filepath.Join(dir, "repo")
|
||||
err = checkout(repoUrl, target)
|
||||
repodir := filepath.Join(dir, "repo")
|
||||
src, subdir := getter.SourceDirSubdir(repoUrl)
|
||||
err = checkout(src, repodir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target := filepath.Join(repodir, subdir)
|
||||
l := newFileLoaderAtRoot(target, fs)
|
||||
return &githubLoader{
|
||||
repo: repoUrl,
|
||||
checkoutDir: dir,
|
||||
targetDir: target,
|
||||
checkoutDir: repodir,
|
||||
loader: l,
|
||||
}, nil
|
||||
}
|
||||
@@ -78,6 +84,9 @@ func isRepoUrl(s string) bool {
|
||||
if strings.HasPrefix(s, "https://") {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(s, "git::") {
|
||||
return true
|
||||
}
|
||||
host := strings.SplitN(s, "/", 2)[0]
|
||||
return strings.Contains(host, ".com") || strings.Contains(host, ".org")
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ func TestIsRepoURL(t *testing.T) {
|
||||
input: "../relative",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "git::https://gitlab.com/org/repo",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
actual := isRepoUrl(tc.input)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
// Loader interface exposes methods to read bytes.
|
||||
|
||||
40
pkg/patch/jsonpatch.go
Normal file
40
pkg/patch/jsonpatch.go
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package patch
|
||||
|
||||
// PatchJson6902 represents a json patch for an object
|
||||
// with format documented https://tools.ietf.org/html/rfc6902.
|
||||
type PatchJson6902 struct {
|
||||
// Target 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. Target should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix).
|
||||
Target *Target `json:"target" yaml:"target"`
|
||||
|
||||
// relative file path for a json patch file inside a kustomization
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
}
|
||||
|
||||
// Target represents the kubernetes object that the patch is applied to
|
||||
type Target struct {
|
||||
Group string `json:"group,omitempty" yaml:"group,omitempty"`
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
}
|
||||
40
pkg/patch/strategicmergepatch.go
Normal file
40
pkg/patch/strategicmergepatch.go
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package patch
|
||||
|
||||
// PatchStrategicMerge represents a relative path to a
|
||||
// stategic merget patch with the format
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
|
||||
type PatchStrategicMerge string
|
||||
|
||||
// Append appends a slice of patch paths to a PatchStategicMerge slice
|
||||
func Append(patches []PatchStrategicMerge, paths ...string) []PatchStrategicMerge {
|
||||
for _, p := range paths {
|
||||
patches = append(patches, PatchStrategicMerge(p))
|
||||
}
|
||||
return patches
|
||||
}
|
||||
|
||||
// Exist determines if a patch path exists in a slice of PatchStategicMerge
|
||||
func Exist(patches []PatchStrategicMerge, path string) bool {
|
||||
for _, p := range patches {
|
||||
if p == PatchStrategicMerge(path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
95
pkg/patch/transformer/factory.go
Normal file
95
pkg/patch/transformer/factory.go
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/evanphx/json-patch"
|
||||
"github.com/krishicks/yaml-patch"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/pkg/patch"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
)
|
||||
|
||||
// PatchJson6902Factory makes PatchJson6902 transformers
|
||||
type PatchJson6902Factory struct {
|
||||
loader loader.Loader
|
||||
}
|
||||
|
||||
// NewPatchJson6902Factory returns a new PatchJson6902Factory.
|
||||
func NewPatchJson6902Factory(l loader.Loader) PatchJson6902Factory {
|
||||
return PatchJson6902Factory{loader: l}
|
||||
}
|
||||
|
||||
// MakePatchJson6902Transformer returns a transformer for applying Json6902 patch
|
||||
func (f PatchJson6902Factory) MakePatchJson6902Transformer(patches []patch.PatchJson6902) (transformers.Transformer, error) {
|
||||
var ts []transformers.Transformer
|
||||
for _, p := range patches {
|
||||
t, err := f.makeOnePatchJson6902Transformer(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t != nil {
|
||||
ts = append(ts, t)
|
||||
}
|
||||
}
|
||||
return transformers.NewMultiTransformerWithConflictCheck(ts), nil
|
||||
}
|
||||
|
||||
func (f PatchJson6902Factory) makeOnePatchJson6902Transformer(p patch.PatchJson6902) (transformers.Transformer, error) {
|
||||
if p.Target == nil {
|
||||
return nil, fmt.Errorf("must specify the target field in patchesJson6902")
|
||||
}
|
||||
if p.Path == "" {
|
||||
return nil, fmt.Errorf("must specify the path for a json patch file")
|
||||
}
|
||||
|
||||
targetId := resource.NewResIdWithPrefixNamespace(
|
||||
schema.GroupVersionKind{
|
||||
Group: p.Target.Group,
|
||||
Version: p.Target.Version,
|
||||
Kind: p.Target.Kind,
|
||||
},
|
||||
p.Target.Name,
|
||||
"",
|
||||
p.Target.Namespace,
|
||||
)
|
||||
|
||||
rawOp, err := f.loader.Load(p.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isJsonFormat(rawOp) {
|
||||
decodedPatch, err := jsonpatch.DecodePatch(rawOp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newPatchJson6902JSONTransformer(targetId, decodedPatch)
|
||||
}
|
||||
decodedPatch, err := yamlpatch.DecodePatch(rawOp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newPatchJson6902YAMLTransformer(targetId, decodedPatch)
|
||||
}
|
||||
|
||||
func isJsonFormat(data []byte) bool {
|
||||
return data[0] == '['
|
||||
}
|
||||
331
pkg/patch/transformer/factory_test.go
Normal file
331
pkg/patch/transformer/factory_test.go
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||
"sigs.k8s.io/kustomize/pkg/patch"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
func TestNewPatchJson6902FactoryNoTarget(t *testing.T) {
|
||||
p := patch.PatchJson6902{}
|
||||
_, err := NewPatchJson6902Factory(nil).makeOnePatchJson6902Transformer(p)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "must specify the target field in patchesJson6902") {
|
||||
t.Fatalf("incorrect error returned: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatchJson6902FactoryConflict(t *testing.T) {
|
||||
jsonPatch := []byte(`
|
||||
target:
|
||||
name: some-name
|
||||
kind: Deployment
|
||||
`)
|
||||
p := patch.PatchJson6902{}
|
||||
err := yaml.Unmarshal(jsonPatch, &p)
|
||||
if err != nil {
|
||||
t.Fatalf("expected error %v", err)
|
||||
}
|
||||
f := NewPatchJson6902Factory(nil)
|
||||
_, err = f.makeOnePatchJson6902Transformer(p)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "must specify the path for a json patch file") {
|
||||
t.Fatalf("incorrect error returned %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatchJson6902FactoryJSON(t *testing.T) {
|
||||
ldr := loadertest.NewFakeLoader("/testpath")
|
||||
operations := []byte(`[
|
||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"},
|
||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||
]`)
|
||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
|
||||
jsonPatch := []byte(`
|
||||
target:
|
||||
kind: Deployment
|
||||
name: some-name
|
||||
path: /testpath/patch.json
|
||||
`)
|
||||
p := patch.PatchJson6902{}
|
||||
err = yaml.Unmarshal(jsonPatch, &p)
|
||||
if err != nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
tr, err := NewPatchJson6902Factory(ldr).makeOnePatchJson6902Transformer(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
if tr == nil {
|
||||
t.Fatal("the returned transformer should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatchJson6902FactoryYAML(t *testing.T) {
|
||||
ldr := loadertest.NewFakeLoader("/testpath")
|
||||
operations := []byte(`
|
||||
- op: replace
|
||||
path: /spec/template/spec/containers/0/name
|
||||
value: my-nginx
|
||||
- op: add
|
||||
path: /spec/replica
|
||||
value: 3
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/command
|
||||
value: ["arg1", "arg2", "arg3"]
|
||||
`)
|
||||
err := ldr.AddFile("/testpath/patch.yaml", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
jsonPatch := []byte(`
|
||||
target:
|
||||
name: some-name
|
||||
kind: Deployment
|
||||
path: /testpath/patch.yaml
|
||||
`)
|
||||
p := patch.PatchJson6902{}
|
||||
err = yaml.Unmarshal(jsonPatch, &p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
|
||||
tr, err := NewPatchJson6902Factory(ldr).makeOnePatchJson6902Transformer(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
if tr == nil {
|
||||
t.Fatal("the returned transformer should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatchJson6902FactoryMulti(t *testing.T) {
|
||||
ldr := loadertest.NewFakeLoader("/testpath")
|
||||
operations := []byte(`[
|
||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
||||
]`)
|
||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
|
||||
operations = []byte(`
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/command
|
||||
value: ["arg1", "arg2", "arg3"]
|
||||
`)
|
||||
err = ldr.AddFile("/testpath/patch.yaml", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
|
||||
jsonPatches := []byte(`
|
||||
- target:
|
||||
kind: foo
|
||||
name: some-name
|
||||
path: /testpath/patch.json
|
||||
|
||||
- target:
|
||||
kind: foo
|
||||
name: some-name
|
||||
path: /testpath/patch.yaml
|
||||
`)
|
||||
var p []patch.PatchJson6902
|
||||
err = yaml.Unmarshal(jsonPatches, &p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
|
||||
f := NewPatchJson6902Factory(ldr)
|
||||
tr, err := f.MakePatchJson6902Transformer(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
if tr == nil {
|
||||
t.Fatal("the returned transformer should not be nil")
|
||||
}
|
||||
|
||||
id := resource.NewResId(schema.GroupVersionKind{Kind: "foo"}, "some-name")
|
||||
base := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"kind": "foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "some-name",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"image": "nginx",
|
||||
"name": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
expected := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"kind": "foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "some-name",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replica": "3",
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"image": "nginx",
|
||||
"name": "my-nginx",
|
||||
"command": []interface{}{
|
||||
"arg1",
|
||||
"arg2",
|
||||
"arg3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
err = tr.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = expected.ErrorIfNotEqual(base)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatchJson6902FactoryMultiConflict(t *testing.T) {
|
||||
ldr := loadertest.NewFakeLoader("/testpath")
|
||||
operations := []byte(`[
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
||||
]`)
|
||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
operations = []byte(`
|
||||
- op: add
|
||||
path: /spec/replica
|
||||
value: 4
|
||||
`)
|
||||
err = ldr.AddFile("/testpath/patch.yaml", operations)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
|
||||
jsonPatches := []byte(`
|
||||
- target:
|
||||
kind: foo
|
||||
name: some-name
|
||||
path: /testpath/patch.json
|
||||
|
||||
- target:
|
||||
kind: foo
|
||||
name: some-name
|
||||
path: /testpath/patch.yaml
|
||||
`)
|
||||
var p []patch.PatchJson6902
|
||||
err = yaml.Unmarshal(jsonPatches, &p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
|
||||
f := NewPatchJson6902Factory(ldr)
|
||||
tr, err := f.MakePatchJson6902Transformer(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
if tr == nil {
|
||||
t.Fatal("the returned transformer should not be nil")
|
||||
}
|
||||
|
||||
id := resource.NewResId(schema.GroupVersionKind{Kind: "foo"}, "some-name")
|
||||
base := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"kind": "foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "somename",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"image": "nginx",
|
||||
"name": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
err = tr.Transform(base)
|
||||
if err == nil {
|
||||
t.Fatal("expected conflict")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "found conflict between different patches") {
|
||||
t.Fatalf("incorrect error happened %v", err)
|
||||
}
|
||||
}
|
||||
61
pkg/patch/transformer/patchjson6902json.go
Normal file
61
pkg/patch/transformer/patchjson6902json.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"github.com/evanphx/json-patch"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
)
|
||||
|
||||
// patchJson6902JSONTransformer applies patches.
|
||||
type patchJson6902JSONTransformer struct {
|
||||
target resource.ResId
|
||||
patch jsonpatch.Patch
|
||||
}
|
||||
|
||||
var _ transformers.Transformer = &patchJson6902JSONTransformer{}
|
||||
|
||||
// newPatchJson6902JSONTransformer constructs a PatchJson6902 transformer.
|
||||
func newPatchJson6902JSONTransformer(t resource.ResId, p jsonpatch.Patch) (transformers.Transformer, error) {
|
||||
if len(p) == 0 {
|
||||
return transformers.NewNoOpTransformer(), nil
|
||||
}
|
||||
return &patchJson6902JSONTransformer{target: t, patch: p}, nil
|
||||
}
|
||||
|
||||
// Transform apply the json patches on top of the base resources.
|
||||
func (t *patchJson6902JSONTransformer) Transform(baseResourceMap resmap.ResMap) error {
|
||||
obj, err := findTargetObj(baseResourceMap, t.target)
|
||||
if obj == nil {
|
||||
return err
|
||||
}
|
||||
rawObj, err := obj.Unstructured.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modifiedObj, err := t.patch.Apply(rawObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = obj.UnmarshalJSON(modifiedObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
112
pkg/patch/transformer/patchjson6902json_test.go
Normal file
112
pkg/patch/transformer/patchjson6902json_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/evanphx/json-patch"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
||||
id := resource.NewResId(deploy, "deploy1")
|
||||
base := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
operations := []byte(`[
|
||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||
{"op": "add", "path": "/spec/replica", "value": "3"},
|
||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||
]`)
|
||||
patch, err := jsonpatch.DecodePatch(operations)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
expected := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replica": "3",
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"image": "nginx",
|
||||
"name": "my-nginx",
|
||||
"command": []interface{}{
|
||||
"arg1",
|
||||
"arg2",
|
||||
"arg3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
jpt, err := newPatchJson6902JSONTransformer(id, patch)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
err = jpt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = expected.ErrorIfNotEqual(base)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
62
pkg/patch/transformer/patchjson6902yaml.go
Normal file
62
pkg/patch/transformer/patchjson6902yaml.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/krishicks/yaml-patch"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||
)
|
||||
|
||||
// patchJson6902YAMLTransformer applies patches.
|
||||
type patchJson6902YAMLTransformer struct {
|
||||
target resource.ResId
|
||||
patch yamlpatch.Patch
|
||||
}
|
||||
|
||||
var _ transformers.Transformer = &patchJson6902YAMLTransformer{}
|
||||
|
||||
// newPatchJson6902YAMLTransformer constructs a PatchJson6902 transformer.
|
||||
func newPatchJson6902YAMLTransformer(t resource.ResId, p yamlpatch.Patch) (transformers.Transformer, error) {
|
||||
if len(p) == 0 {
|
||||
return transformers.NewNoOpTransformer(), nil
|
||||
}
|
||||
return &patchJson6902YAMLTransformer{target: t, patch: p}, nil
|
||||
}
|
||||
|
||||
// Transform apply the json patches on top of the base resources.
|
||||
func (t *patchJson6902YAMLTransformer) Transform(baseResourceMap resmap.ResMap) error {
|
||||
obj, err := findTargetObj(baseResourceMap, t.target)
|
||||
if obj == nil {
|
||||
return err
|
||||
}
|
||||
rawObj, err := yaml.Marshal(obj.Unstructured.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modifiedObj, err := t.patch.Apply(rawObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = yaml.Unmarshal(modifiedObj, &obj.Unstructured.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
128
pkg/patch/transformer/patchjson6902yaml_test.go
Normal file
128
pkg/patch/transformer/patchjson6902yaml_test.go
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/krishicks/yaml-patch"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}
|
||||
|
||||
func TestJsonPatchYAMLTransformer_Transform(t *testing.T) {
|
||||
id := resource.NewResId(deploy, "deploy1")
|
||||
base := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
var image, replica, command interface{}
|
||||
image = "my-nginx"
|
||||
replica = "3"
|
||||
command = []string{"arg1", "arg2", "arg3"}
|
||||
patch := yamlpatch.Patch{
|
||||
{
|
||||
Op: "replace",
|
||||
Path: "/spec/template/spec/containers/0/name",
|
||||
Value: yamlpatch.NewNode(&image),
|
||||
},
|
||||
{
|
||||
Op: "add",
|
||||
Path: "/spec/replica",
|
||||
Value: yamlpatch.NewNode(&replica),
|
||||
},
|
||||
{
|
||||
Op: "add",
|
||||
Path: "/spec/template/spec/containers/0/command",
|
||||
Value: yamlpatch.NewNode(&command),
|
||||
},
|
||||
}
|
||||
|
||||
expected := resmap.ResMap{
|
||||
id: resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"replica": "3",
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"image": "nginx",
|
||||
"name": "my-nginx",
|
||||
"command": []interface{}{
|
||||
"arg1",
|
||||
"arg2",
|
||||
"arg3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
jpt, err := newPatchJson6902YAMLTransformer(id, patch)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error : %v", err)
|
||||
}
|
||||
err = jpt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = expected.ErrorIfNotEqual(base)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
47
pkg/patch/transformer/util.go
Normal file
47
pkg/patch/transformer/util.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
func findTargetObj(m resmap.ResMap, targetId resource.ResId) (*resource.Resource, error) {
|
||||
matchedIds := m.FindByGVKN(targetId)
|
||||
if targetId.Namespace() != "" {
|
||||
var ids []resource.ResId
|
||||
for _, id := range matchedIds {
|
||||
if id.Namespace() == targetId.Namespace() {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
matchedIds = ids
|
||||
}
|
||||
|
||||
if len(matchedIds) == 0 {
|
||||
log.Printf("Couldn't find any object to apply the json patch %v, skipping it.", targetId)
|
||||
return nil, nil
|
||||
}
|
||||
if len(matchedIds) > 1 {
|
||||
return nil, fmt.Errorf("found multiple objects that the patch can apply %v", matchedIds)
|
||||
}
|
||||
return m[matchedIds[0]], nil
|
||||
}
|
||||
@@ -17,9 +17,9 @@ limitations under the License.
|
||||
package resmap
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resource"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"sigs.k8s.io/kustomize/pkg/configmapandsecret"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
// NewResMapFromConfigMapArgs returns a Resource slice given
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/internal/loadertest"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resource"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/configmapandsecret"
|
||||
"sigs.k8s.io/kustomize/pkg/fs"
|
||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/pkg/types"
|
||||
)
|
||||
|
||||
var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}
|
||||
|
||||
@@ -19,8 +19,8 @@ package resmap
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resource"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/kustomize/pkg/resource"
|
||||
)
|
||||
|
||||
// IdSlice implements the sort interface.
|
||||
@@ -34,7 +34,7 @@ func (a IdSlice) Less(i, j int) bool {
|
||||
if a[i].Gvk().String() != a[j].Gvk().String() {
|
||||
return gvkLess(a[i].Gvk(), a[j].Gvk())
|
||||
}
|
||||
return a[i].Name() < a[j].Name()
|
||||
return a[i].String() < a[j].String()
|
||||
}
|
||||
|
||||
var order = []string{"Namespace", "CustomResourceDefinition", "ServiceAccount",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user