mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-07-18 18:18:36 +00:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95f3303493 | ||
|
|
2faf4a491b | ||
|
|
e646bba1ff | ||
|
|
99a21b0a3c | ||
|
|
e7a22b6bc5 | ||
|
|
d783bbc0bc | ||
|
|
b7405f3872 | ||
|
|
abc419b5f9 | ||
|
|
336378b114 | ||
|
|
29959551da | ||
|
|
fc78917191 | ||
|
|
ffd95ef5a9 | ||
|
|
230090d790 | ||
|
|
8fa3861ba3 | ||
|
|
69c90e3427 | ||
|
|
5a73f345fd | ||
|
|
0e62d759f0 | ||
|
|
b2967d2f77 | ||
|
|
c23039c07a | ||
|
|
5747c417c4 | ||
|
|
8c53d77111 | ||
|
|
01667cabde | ||
|
|
f649b62629 | ||
|
|
3a4d025b5c | ||
|
|
99eb08eb1e | ||
|
|
d3f8c0d87f | ||
|
|
0bec7b996b | ||
|
|
dd5674fe6b | ||
|
|
33159c26df | ||
|
|
afc7dbebe5 | ||
|
|
f363acf839 | ||
|
|
96d5a7401d | ||
|
|
403fa20546 | ||
|
|
ba4d7ddca8 | ||
|
|
5116e2f210 | ||
|
|
9e0f198227 | ||
|
|
30b378a924 | ||
|
|
3a843f1eca | ||
|
|
9b40f8ab47 | ||
|
|
dc6dcd8150 | ||
|
|
3cb6c7f1f4 | ||
|
|
7632839bc8 | ||
|
|
c3ea109b59 | ||
|
|
579995dc8a | ||
|
|
b43bd5440d | ||
|
|
c4d899f7f3 | ||
|
|
7998ee7036 | ||
|
|
878960d7b1 | ||
|
|
ed0cfc685b | ||
|
|
b0a7345123 | ||
|
|
580963ea76 | ||
|
|
0707deae95 | ||
|
|
fb44880b8c | ||
|
|
e5ebca6604 | ||
|
|
f5fc9acb84 | ||
|
|
28d1bad3cb | ||
|
|
6f74419628 | ||
|
|
8121467c1e | ||
|
|
a85f297f31 | ||
|
|
76a7816aeb | ||
|
|
7872405379 | ||
|
|
6c17a3409f | ||
|
|
f1dbab9dee | ||
|
|
bfafbbf47f | ||
|
|
08d7c35da7 | ||
|
|
f12704f6c1 | ||
|
|
0edab60b30 | ||
|
|
3c05e2d664 | ||
|
|
aa2313c282 | ||
|
|
eeed1954fb | ||
|
|
cd00ce7ab1 | ||
|
|
145d07363f | ||
|
|
33fff655db | ||
|
|
31ab347da2 | ||
|
|
7a48b2ba8e | ||
|
|
876f2a8236 | ||
|
|
095333ffb1 | ||
|
|
0d8d9e2f2b | ||
|
|
9bff2e8883 | ||
|
|
120ba6b870 | ||
|
|
483188ba89 | ||
|
|
672bda0c9c | ||
|
|
49b32473ca | ||
|
|
08400d77a6 | ||
|
|
c912baeb3a | ||
|
|
433733eb0e | ||
|
|
f996ac82c7 | ||
|
|
efcb7cc5a5 | ||
|
|
bf7b57537b | ||
|
|
6b597f8711 | ||
|
|
088739900f | ||
|
|
3bf13f83d3 | ||
|
|
c64a72f1f9 | ||
|
|
8b60b456ac |
@@ -1,5 +1,7 @@
|
|||||||
# kustomize
|
# kustomize
|
||||||
|
|
||||||
|
_[v3.0.2](https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.0.2) is the latest release._
|
||||||
|
|
||||||
`kustomize` lets you customize raw, template-free YAML
|
`kustomize` lets you customize raw, template-free YAML
|
||||||
files for multiple purposes, leaving the original YAML
|
files for multiple purposes, leaving the original YAML
|
||||||
untouched and usable as is.
|
untouched and usable as is.
|
||||||
@@ -22,7 +24,7 @@ these [instructions](docs/INSTALL.md).
|
|||||||
Browse the [docs](docs) or jump right into the
|
Browse the [docs](docs) or jump right into the
|
||||||
tested [examples](examples).
|
tested [examples](examples).
|
||||||
|
|
||||||
kustomize [v2.0.3] is available in [kubectl v1.15][kubectl].
|
kustomize [v2.0.3] is available in [kubectl v1.14 and v1.15][kubectl].
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
28
docs/FAQ.md
28
docs/FAQ.md
@@ -28,3 +28,31 @@ To disable this, use v3, and the `load_restrictor` flag:
|
|||||||
```
|
```
|
||||||
kustomize build --load_restrictor none $target
|
kustomize build --load_restrictor none $target
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Some field is not transformed by kustomize
|
||||||
|
|
||||||
|
Example: [#1319](https://github.com/kubernetes-sigs/kustomize/issues/1319), [#1322](https://github.com/kubernetes-sigs/kustomize/issues/1322), [#1347](https://github.com/kubernetes-sigs/kustomize/issues/1347) and etc.
|
||||||
|
|
||||||
|
The fields transformed by kustomize is configured explicitly in [defaultconfig](https://github.com/kubernetes-sigs/kustomize/tree/master/pkg/transformers/config/defaultconfig). The configuration itself can be customized by including `configurations` in `kustomization.yaml`, e.g.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
configurations:
|
||||||
|
- kustomizeconfig.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
The configuration directive allows customization of the following transformers:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
commonAnnotations: []
|
||||||
|
commonLabels: []
|
||||||
|
nameprefix: []
|
||||||
|
namespace: []
|
||||||
|
varreference: []
|
||||||
|
namereference: []
|
||||||
|
images: []
|
||||||
|
replicas: []
|
||||||
|
```
|
||||||
|
|
||||||
|
To persist the changes to default configuration, submit a PR like [#1338](https://github.com/kubernetes-sigs/kustomize/pull/1338), [#1348](https://github.com/kubernetes-sigs/kustomize/pull/1348) and etc.
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ English | [简体中文](zh/README.md)
|
|||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
|
||||||
* [3.0](v3.0.0.md) - Late June 2019. Plugin developer release.
|
* [3.1](v3.1.0.md) - Late July 2019. Extended patches and improved resource matching.
|
||||||
|
|
||||||
|
* [3.0](v3.0.0.md) - Late June 2019. Plugin developer release.
|
||||||
|
|
||||||
* [2.1](v2.1.0.md) - 18 June 2019. Plugins, ordered resources, etc.
|
* [2.1](v2.1.0.md) - 18 June 2019. Plugins, ordered resources, etc.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
# Go Plugin Guided Example for Linux
|
# Go Plugin Guided Example for Linux
|
||||||
|
|
||||||
This is a (no reading allowed!) 60 second copy/paste guided
|
|
||||||
example. Full plugin docs [here](README.md).
|
|
||||||
|
|
||||||
[SopsEncodedSecrets repository]: https://github.com/monopole/sopsencodedsecrets
|
[SopsEncodedSecrets repository]: https://github.com/monopole/sopsencodedsecrets
|
||||||
[Go plugin]: https://golang.org/pkg/plugin
|
[Go plugin]: https://golang.org/pkg/plugin
|
||||||
|
[Go plugin caveats]: goPluginCaveats.md
|
||||||
|
|
||||||
|
This is a (no reading allowed!) 60 second copy/paste guided
|
||||||
|
example.
|
||||||
|
|
||||||
|
Full plugin docs [here](README.md).
|
||||||
|
Be sure to read the [Go plugin caveats].
|
||||||
|
|
||||||
This demo uses a Go plugin, `SopsEncodedSecrets`,
|
This demo uses a Go plugin, `SopsEncodedSecrets`,
|
||||||
that lives in the [sopsencodedsecrets repository].
|
that lives in the [sopsencodedsecrets repository].
|
||||||
@@ -17,23 +21,32 @@ current setup.
|
|||||||
|
|
||||||
#### requirements
|
#### requirements
|
||||||
|
|
||||||
* linux, git, curl, Go 1.12
|
* linux, git, curl, Go 1.12
|
||||||
* Google cloud (gcloud) install
|
|
||||||
* a Google account (will use Google kms -
|
For encryption
|
||||||
volunteers needed to convert to a GPG example).
|
|
||||||
|
* gpg
|
||||||
|
|
||||||
|
Or
|
||||||
|
|
||||||
|
* Google cloud (gcloud) install
|
||||||
|
* a Google account with KMS permission
|
||||||
|
|
||||||
## Make a place to work
|
## Make a place to work
|
||||||
|
|
||||||
```
|
```shell
|
||||||
|
# Keeping these separate to avoid cluttering the DEMO dir.
|
||||||
DEMO=$(mktemp -d)
|
DEMO=$(mktemp -d)
|
||||||
|
tmpGoPath=$(mktemp -d)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Install kustomize
|
## Install kustomize
|
||||||
|
|
||||||
Need v3.0.0 for what follows:
|
Need v3.0.0 for what follows, and you must _compile_
|
||||||
|
it (not download the binary from the release page):
|
||||||
|
|
||||||
```
|
```shell
|
||||||
GOBIN=$DEMO/bin go get sigs.k8s.io/kustomize/v3/cmd/kustomize@v3.0.0-pre
|
GOPATH=$tmpGoPath go install sigs.k8s.io/kustomize/v3/cmd/kustomize
|
||||||
```
|
```
|
||||||
|
|
||||||
## Make a home for plugins
|
## Make a home for plugins
|
||||||
@@ -54,7 +67,7 @@ The kustomize program reads the config file
|
|||||||
kustomization file), then locates the Go plugin's
|
kustomization file), then locates the Go plugin's
|
||||||
object code at the following location:
|
object code at the following location:
|
||||||
|
|
||||||
> ```
|
> ```shell
|
||||||
> $XGD_CONFIG_HOME/kustomize/plugin/$apiVersion/$lKind/$kind.so
|
> $XGD_CONFIG_HOME/kustomize/plugin/$apiVersion/$lKind/$kind.so
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
@@ -74,7 +87,7 @@ left to plugins to find their own config.
|
|||||||
This demo will house the plugin it uses at the
|
This demo will house the plugin it uses at the
|
||||||
ephemeral directory
|
ephemeral directory
|
||||||
|
|
||||||
```
|
```shell
|
||||||
PLUGIN_ROOT=$DEMO/kustomize/plugin
|
PLUGIN_ROOT=$DEMO/kustomize/plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -100,7 +113,7 @@ and it lives in the [SopsEncodedSecrets repository].
|
|||||||
Somewhat arbitrarily, we'll chose to install
|
Somewhat arbitrarily, we'll chose to install
|
||||||
this plugin with
|
this plugin with
|
||||||
|
|
||||||
```
|
```shell
|
||||||
apiVersion=mygenerators
|
apiVersion=mygenerators
|
||||||
kind=SopsEncodedSecrets
|
kind=SopsEncodedSecrets
|
||||||
```
|
```
|
||||||
@@ -111,7 +124,7 @@ By convention, the ultimate home of the plugin
|
|||||||
code and supplemental data, tests, documentation,
|
code and supplemental data, tests, documentation,
|
||||||
etc. is the lowercase form of its kind.
|
etc. is the lowercase form of its kind.
|
||||||
|
|
||||||
```
|
```shell
|
||||||
lKind=$(echo $kind | awk '{print tolower($0)}')
|
lKind=$(echo $kind | awk '{print tolower($0)}')
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -121,7 +134,7 @@ In this case, the repo name matches the lowercase
|
|||||||
kind already, so we just clone the repo and get
|
kind already, so we just clone the repo and get
|
||||||
the proper directory name automatically:
|
the proper directory name automatically:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
mkdir -p $PLUGIN_ROOT/${apiVersion}
|
mkdir -p $PLUGIN_ROOT/${apiVersion}
|
||||||
cd $PLUGIN_ROOT/${apiVersion}
|
cd $PLUGIN_ROOT/${apiVersion}
|
||||||
git clone git@github.com:monopole/sopsencodedsecrets.git
|
git clone git@github.com:monopole/sopsencodedsecrets.git
|
||||||
@@ -129,7 +142,7 @@ git clone git@github.com:monopole/sopsencodedsecrets.git
|
|||||||
|
|
||||||
Remember this directory:
|
Remember this directory:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
MY_PLUGIN_DIR=$PLUGIN_ROOT/${apiVersion}/${lKind}
|
MY_PLUGIN_DIR=$PLUGIN_ROOT/${apiVersion}/${lKind}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -138,16 +151,16 @@ MY_PLUGIN_DIR=$PLUGIN_ROOT/${apiVersion}/${lKind}
|
|||||||
Plugins may come with their own tests.
|
Plugins may come with their own tests.
|
||||||
This one does, and it hopefully passes:
|
This one does, and it hopefully passes:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cd $MY_PLUGIN_DIR
|
cd $MY_PLUGIN_DIR
|
||||||
go test SopsEncodedSecrets_test.go
|
go test SopsEncodedSecrets_test.go
|
||||||
```
|
```
|
||||||
|
|
||||||
Build the object code for use by kustomize:
|
Build the object code for use by kustomize:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cd $MY_PLUGIN_DIR
|
cd $MY_PLUGIN_DIR
|
||||||
go build -buildmode plugin -o ${kind}.so ${kind}.go
|
GOPATH=$tmpGoPath go build -buildmode plugin -o ${kind}.so ${kind}.go
|
||||||
```
|
```
|
||||||
|
|
||||||
This step may succeed, but kustomize might
|
This step may succeed, but kustomize might
|
||||||
@@ -180,11 +193,11 @@ reusable instead of bizarrely woven throughout the
|
|||||||
code as a individual special cases.
|
code as a individual special cases.
|
||||||
|
|
||||||
## Create a kustomization
|
## Create a kustomization
|
||||||
|
|
||||||
Make a kustomization directory to
|
Make a kustomization directory to
|
||||||
hold all your config:
|
hold all your config:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
MYAPP=$DEMO/myapp
|
MYAPP=$DEMO/myapp
|
||||||
mkdir -p $MYAPP
|
mkdir -p $MYAPP
|
||||||
```
|
```
|
||||||
@@ -194,12 +207,13 @@ Make a config file for the SopsEncodedSecrets plugin.
|
|||||||
Its `apiVersion` and `kind` allow the plugin to be
|
Its `apiVersion` and `kind` allow the plugin to be
|
||||||
found:
|
found:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cat <<EOF >$MYAPP/secGenerator.yaml
|
cat <<EOF >$MYAPP/secGenerator.yaml
|
||||||
apiVersion: ${apiVersion}
|
apiVersion: ${apiVersion}
|
||||||
kind: ${kind}
|
kind: ${kind}
|
||||||
metadata:
|
metadata:
|
||||||
name: forbiddenValues
|
name: mySecretGenerator
|
||||||
|
name: forbiddenValues
|
||||||
namespace: production
|
namespace: production
|
||||||
file: myEncryptedData.yaml
|
file: myEncryptedData.yaml
|
||||||
keys:
|
keys:
|
||||||
@@ -214,7 +228,7 @@ This plugin expects to find more data in
|
|||||||
Make a kustomization file referencing the plugin
|
Make a kustomization file referencing the plugin
|
||||||
config:
|
config:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
cat <<EOF >$MYAPP/kustomization.yaml
|
cat <<EOF >$MYAPP/kustomization.yaml
|
||||||
commonLabels:
|
commonLabels:
|
||||||
app: hello
|
app: hello
|
||||||
@@ -223,31 +237,46 @@ generators:
|
|||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
Now for the hard part. Generate the real encrypted data.
|
Now generate the real encrypted data.
|
||||||
|
|
||||||
|
### Assure you have an encryption tool installed
|
||||||
|
|
||||||
### Assure you have a Google Cloud sops key ring.
|
We're going to use [sops](https://github.com/mozilla/sops) to encode a file. Choose either GPG or Google Cloud KMS as the secret provider to continue.
|
||||||
|
|
||||||
We're going to use [sops](https://github.com/mozilla/sops) to encode a file.
|
#### GPG
|
||||||
|
|
||||||
Try this:
|
Try this:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
gpg --list-keys
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If it returns a list, presumably you've already created keys. If not, try import test keys from sops for dev.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc | gpg --import
|
||||||
|
SOPS_PGP_FP="1022470DE3F0BC54BC6AB62DE05550BC07FB1A0A"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Google Cloude KMS
|
||||||
|
|
||||||
|
Try this:
|
||||||
|
|
||||||
|
```shell
|
||||||
gcloud kms keys list --location global --keyring sops
|
gcloud kms keys list --location global --keyring sops
|
||||||
```
|
```
|
||||||
|
|
||||||
If it succeeds, presumably you've already
|
If it succeeds, presumably you've already created keys and placed them in a keyring called sops. If not, do this:
|
||||||
created keys and placed them in a keyring called `sops`.
|
|
||||||
If not, do this:
|
|
||||||
|
|
||||||
```
|
```shell
|
||||||
gcloud kms keyrings create sops --location global
|
gcloud kms keyrings create sops --location global
|
||||||
gcloud kms keys create sops-key --location global \
|
gcloud kms keys create sops-key --location global \
|
||||||
--keyring sops --purpose encryption
|
--keyring sops --purpose encryption
|
||||||
```
|
```
|
||||||
|
|
||||||
Extract your keyLocation for use below:
|
Extract your keyLocation for use below:
|
||||||
```
|
|
||||||
|
```shell
|
||||||
keyLocation=$(\
|
keyLocation=$(\
|
||||||
gcloud kms keys list --location global --keyring sops |\
|
gcloud kms keys list --location global --keyring sops |\
|
||||||
grep GOOGLE | cut -d " " -f1)
|
grep GOOGLE | cut -d " " -f1)
|
||||||
@@ -256,42 +285,73 @@ echo $keyLocation
|
|||||||
|
|
||||||
### Install `sops`
|
### Install `sops`
|
||||||
|
|
||||||
```
|
```shell
|
||||||
GOBIN=$DEMO/bin go install go.mozilla.org/sops/cmd/sops
|
GOPATH=$tmpGoPath go install go.mozilla.org/sops/cmd/sops
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create data encrypted with your Google Cloud key
|
### Create data encrypted with your private key
|
||||||
|
|
||||||
Create raw data to encrypt:
|
Create raw data to encrypt:
|
||||||
```
|
|
||||||
|
```shell
|
||||||
cat <<EOF >$MYAPP/myClearData.yaml
|
cat <<EOF >$MYAPP/myClearData.yaml
|
||||||
VEGETABLE: carrot
|
VEGETABLE: carrot
|
||||||
ROCKET: saturn-v
|
ROCKET: saturn-v
|
||||||
FRUIT: apple
|
FRUIT: apple
|
||||||
CAR: dymaxion
|
CAR: dymaxion
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Encrypt the data into file the plugin wants to read:
|
Encrypt the data into file the plugin wants to read:
|
||||||
|
|
||||||
|
With PGP
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$tmpGoPath/bin/sops --encrypt \
|
||||||
|
--pgp $SOPS_PGP_FP \
|
||||||
|
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
|
||||||
```
|
```
|
||||||
$DEMO/bin/sops --encrypt \
|
|
||||||
|
Or GCP KMS
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$tmpGoPath/bin/sops --encrypt \
|
||||||
--gcp-kms $keyLocation \
|
--gcp-kms $keyLocation \
|
||||||
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
|
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Review the files
|
Review the files
|
||||||
```
|
|
||||||
|
```shell
|
||||||
tree $DEMO
|
tree $DEMO
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This should look something like:
|
||||||
|
|
||||||
|
> ```shell
|
||||||
|
> /tmp/tmp.0kIE9VclPt
|
||||||
|
> ├── kustomize
|
||||||
|
> │ └── plugin
|
||||||
|
> │ └── mygenerators
|
||||||
|
> │ └── sopsencodedsecrets
|
||||||
|
> │ ├── go.mod
|
||||||
|
> │ ├── go.sum
|
||||||
|
> │ ├── LICENSE
|
||||||
|
> │ ├── README.md
|
||||||
|
> │ ├── SopsEncodedSecrets.go
|
||||||
|
> │ ├── SopsEncodedSecrets.so
|
||||||
|
> │ └── SopsEncodedSecrets_test.go
|
||||||
|
> └── myapp
|
||||||
|
> ├── kustomization.yaml
|
||||||
|
> ├── myClearData.yaml
|
||||||
|
> ├── myEncryptedData.yaml
|
||||||
|
> └── secGenerator.yaml
|
||||||
|
> ```
|
||||||
|
|
||||||
## Build your app, using the plugin:
|
## Build your app, using the plugin:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
XDG_CONFIG_HOME=$DEMO $DEMO/bin/kustomize build --enable_alpha_plugins $MYAPP
|
XDG_CONFIG_HOME=$DEMO $tmpGoPath/bin/kustomize build --enable_alpha_plugins $MYAPP
|
||||||
```
|
```
|
||||||
|
|
||||||
This should emit a kubernetes secret, with
|
This should emit a kubernetes secret, with
|
||||||
@@ -299,10 +359,9 @@ encrypted data for the names `ROCKET` and `CAR`.
|
|||||||
|
|
||||||
Above, if you had set
|
Above, if you had set
|
||||||
|
|
||||||
> ```
|
> ```shell
|
||||||
> PLUGIN_ROOT=$HOME/.config/kustomize/plugin
|
> PLUGIN_ROOT=$HOME/.config/kustomize/plugin
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
there would be no need to use `XDG_CONFIG_HOME` in the
|
there would be no need to use `XDG_CONFIG_HOME` in the
|
||||||
_kustomize_ command above.
|
_kustomize_ command above.
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
# kustomize 3.0.0
|
# kustomize 3.0.0
|
||||||
|
|
||||||
This release is basically [v2.1.0](v2.1.0.md),
|
This release is basically [v2.1.0](v2.1.0.md),
|
||||||
with some post-v2.1.0 bugs fixed and a `v3` in Go
|
with many post-v2.1.0 bugs fixed (in about 150
|
||||||
package paths.
|
commits) and a `v3` in Go package paths.
|
||||||
|
|
||||||
[plugin]: https://github.com/kubernetes-sigs/kustomize/tree/master/docs/plugins
|
[plugin]: https://github.com/kubernetes-sigs/kustomize/tree/master/docs/plugins
|
||||||
|
|
||||||
The major version increment to `v3` puts a new
|
The major version increment to `v3` puts a new
|
||||||
floor on a stable API for [plugin] developers
|
floor on a stable API for [plugin] developers
|
||||||
(both _Go_ plugin developers and _exec_ plugin
|
(both _Go_ plugin developers and _exec_ plugin
|
||||||
developers who happen to use Go), to carry them
|
developers who happen to use Go).
|
||||||
through the coming series of minor releases and
|
|
||||||
patches.
|
|
||||||
|
|
||||||
|
|
||||||
### Why so soon after v2.1.0?
|
### Why so soon after v2.1.0?
|
||||||
|
|
||||||
|
|||||||
127
docs/v3.1.0.md
Normal file
127
docs/v3.1.0.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# kustomize 3.1.0
|
||||||
|
|
||||||
|
|
||||||
|
## Extended patches
|
||||||
|
Since this version, Kustomize allows applying one patch to multiple resources. This works for both Strategic Merge Patch and JSON Patch. Take a look at [patch multiple objects](../examples/patchMultipleObjects.md).
|
||||||
|
|
||||||
|
## Improved Resource Matching
|
||||||
|
|
||||||
|
Multiple improvements have been made to allow the user to leverage "namespace"
|
||||||
|
instead/or with "name suffix/prefix" to segregate resources.
|
||||||
|
|
||||||
|
### Patch resolution improvement
|
||||||
|
|
||||||
|
The following example demonstrates how using the namespace field in the patch definition,
|
||||||
|
will let the user define two different patches against two different Deployment having the
|
||||||
|
same "deploy1" name but in different namespaces in the same Kustomize context/folder.
|
||||||
|
Unless the `namespace:` field has been specified in the kustomization.yaml, no namespace
|
||||||
|
value will be handled as Kubernetes `default` namespace.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
namespace: main
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
env:
|
||||||
|
- name: ANOTHERENV
|
||||||
|
value: TESTVALUE
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
namespace: production
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: main
|
||||||
|
env:
|
||||||
|
- name: ANOTHERENV
|
||||||
|
value: PRODVALUE
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Variable resolution improvement
|
||||||
|
|
||||||
|
It is possible to add namespace field to the variable declaration. In the following example,
|
||||||
|
two `Service` objects with the same `elasticsearch` name have been declared.
|
||||||
|
Specifying the namespace in the objRef of the corresponding varriables, allows Kustomize to
|
||||||
|
resovlve thoses variables.
|
||||||
|
If the namespace is not specified, Kustomize will handle it has a "wildcard" value.
|
||||||
|
|
||||||
|
Extract of kustomization.yaml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
vars:
|
||||||
|
- name: elasticsearch-test-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
- name: elasticsearch-dev-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Simultaneous change of names and namespaces
|
||||||
|
|
||||||
|
Kustomize is now able to deal with simultaneous changes of name and namespace.
|
||||||
|
Special attention has been paid the handling of:
|
||||||
|
- ClusterRoleBinding/RoleBinding "subjects" field,
|
||||||
|
- ValidatingWebhookConfiguration "webhooks" field.
|
||||||
|
|
||||||
|
The user should be able to use a kustomization.yaml as shown in the example bellow
|
||||||
|
even if ClusterRoleBind,RoleBinding and ValidatingWebookConfiguration are part of the
|
||||||
|
resources he needs to declare.
|
||||||
|
|
||||||
|
Extract of kustomization.yaml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
namePrefix: pfx-
|
||||||
|
nameSuffix: -sfx
|
||||||
|
namespace: testnamespace
|
||||||
|
|
||||||
|
resources:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource and Kustomize Context matching.
|
||||||
|
|
||||||
|
Kustomize is now able to support more aggregation patterns.
|
||||||
|
|
||||||
|
If for instance, the top level of kustomization.yaml, is simply
|
||||||
|
combining sub-components, (as in the following example), Kustomize has improved
|
||||||
|
resource matching capabilities. This removes some of the constraints which were
|
||||||
|
present on the utilization of prefix/suffix and namespace transformers in the
|
||||||
|
individual components.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resources:
|
||||||
|
- ../component1
|
||||||
|
- ../component2
|
||||||
|
- ../component3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other improvements
|
||||||
|
|
||||||
|
- Image transformation has been improved. This allows the user to update the sha256 of
|
||||||
|
an image with another sha256.
|
||||||
|
- Multiple default transformer configuration entries have been added, removing the need for the
|
||||||
|
user to add them as part of the `configurations:` section of the kustomization.yaml.
|
||||||
|
- `kustomize` help command has been tidied up.
|
||||||
@@ -232,11 +232,11 @@ moment forward.
|
|||||||
[beta-level rules]: https://github.com/kubernetes/community/blob/master/contributors/devel/api_changes.md#alpha-beta-and-stable-versions
|
[beta-level rules]: https://github.com/kubernetes/community/blob/master/contributors/devel/api_changes.md#alpha-beta-and-stable-versions
|
||||||
[changes]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md
|
[changes]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md
|
||||||
[adapt]: https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/types/kustomization.go#L166
|
[adapt]: https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/types/kustomization.go#L166
|
||||||
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#resources
|
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
[k8s API]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
[k8s API]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
||||||
[conventions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
[conventions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
||||||
[release process]: ../releasing/README.md
|
[release process]: ../releasing/README.md
|
||||||
[kustomization]: glossary.md#kustomization
|
[kustomization]: glossary.md#kustomization
|
||||||
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#types-kinds
|
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
[`apiVersion`]: https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning
|
[`apiVersion`]: https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning
|
||||||
[semantic versioning]: https://semver.org
|
[semantic versioning]: https://semver.org
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ Basic Usage
|
|||||||
|
|
||||||
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
|
* [json patch](jsonpatch.md) - Apply a json patch in a kustomization
|
||||||
|
|
||||||
|
* [patch multiple objects](patchMultipleObjects.md) - Apply a patch to multiple objects
|
||||||
|
|
||||||
Advanced Usage
|
Advanced Usage
|
||||||
|
|
||||||
- generator plugins:
|
- generator plugins:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
# before running it.
|
# before running it.
|
||||||
#
|
#
|
||||||
# At time of writing, its 'call point' was in
|
# At time of writing, its 'call point' was in
|
||||||
# https://github.com/kubernetes/test-infra/blob/master/jobs/config.json
|
# https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kustomize/kustomize-config.yaml
|
||||||
|
|
||||||
function exitWith {
|
function exitWith {
|
||||||
local msg=$1
|
local msg=$1
|
||||||
@@ -53,7 +53,7 @@ function setUpEnv {
|
|||||||
exitWith "Script must be run from $expectedRepo"
|
exitWith "Script must be run from $expectedRepo"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
GO111MODULE=on go install . || \
|
GO111MODULE=on go install ./cmd/kustomize || \
|
||||||
{ exitWith "Failed to install kustomize."; }
|
{ exitWith "Failed to install kustomize."; }
|
||||||
|
|
||||||
PATH=$GOPATH/bin:$PATH
|
PATH=$GOPATH/bin:$PATH
|
||||||
|
|||||||
188
examples/patchMultipleObjects.md
Normal file
188
examples/patchMultipleObjects.md
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
[Strategic Merge Patch]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
|
||||||
|
[JSON patches]: https://tools.ietf.org/html/rfc6902
|
||||||
|
[label selector]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
|
||||||
|
|
||||||
|
|
||||||
|
# Demo: applying a patch to multiple resources
|
||||||
|
|
||||||
|
A kustomization file supports customizing resources via both
|
||||||
|
[Strategic Merge Patch] and [JSON patches]. Now one patch can be
|
||||||
|
applied to multiple resources.
|
||||||
|
|
||||||
|
This can be done by specifying a patch and a target selector as follows:
|
||||||
|
```
|
||||||
|
patches:
|
||||||
|
- path: <PatchFile>
|
||||||
|
target:
|
||||||
|
group: <Group>
|
||||||
|
version: <Version>
|
||||||
|
kind: <Kind>
|
||||||
|
name: <Name>
|
||||||
|
namespace: <Namespace>
|
||||||
|
labelSelector: <LabelSelector>
|
||||||
|
annotationSelector: <AnnotationSelector>
|
||||||
|
```
|
||||||
|
Both `labelSelector` and `annotationSelector` should follow the convention in [label selector].
|
||||||
|
Kustomize selects the targets which match all the fields in `target` to apply the patch.
|
||||||
|
|
||||||
|
The example below shows how to inject a sidecar container for all deployment resources.
|
||||||
|
|
||||||
|
Make a `kustomization` containing a Deployment resource.
|
||||||
|
|
||||||
|
<!-- @createDeployment @test -->
|
||||||
|
```
|
||||||
|
DEMO_HOME=$(mktemp -d)
|
||||||
|
|
||||||
|
cat <<EOF >$DEMO_HOME/kustomization.yaml
|
||||||
|
resources:
|
||||||
|
- deployments.yaml
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF >$DEMO_HOME/deployments.yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
|
args:
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: busybox
|
||||||
|
image: busybox
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Declare a Strategic Merge Patch file to inject a sidecar container:
|
||||||
|
|
||||||
|
<!-- @addPatch @test -->
|
||||||
|
```
|
||||||
|
cat <<EOF >$DEMO_HOME/patch.yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: not-important
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: istio-proxy
|
||||||
|
image: docker.io/istio/proxyv2
|
||||||
|
args:
|
||||||
|
- proxy
|
||||||
|
- sidecar
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply the patch by adding _patches_ field in kustomization.yaml
|
||||||
|
|
||||||
|
<!-- @applyPatch @test -->
|
||||||
|
```
|
||||||
|
cat <<EOF >>$DEMO_HOME/kustomization.yaml
|
||||||
|
patches:
|
||||||
|
- path: patch.yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Running `kustomize build $DEMO_HOME`, in the output confirm that both Deployment resources are patched correctly.
|
||||||
|
|
||||||
|
<!-- @confirmPatch @test -->
|
||||||
|
```
|
||||||
|
test 2 == \
|
||||||
|
$(kustomize build $DEMO_HOME | grep "image: docker.io/istio/proxyv2" | wc -l); \
|
||||||
|
echo $?
|
||||||
|
```
|
||||||
|
|
||||||
|
The output is as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- args:
|
||||||
|
- proxy
|
||||||
|
- sidecar
|
||||||
|
image: docker.io/istio/proxyv2
|
||||||
|
name: istio-proxy
|
||||||
|
- args:
|
||||||
|
- one
|
||||||
|
- two
|
||||||
|
image: nginx
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- args:
|
||||||
|
- proxy
|
||||||
|
- sidecar
|
||||||
|
image: docker.io/istio/proxyv2
|
||||||
|
name: istio-proxy
|
||||||
|
- image: busybox
|
||||||
|
name: busybox
|
||||||
|
```
|
||||||
|
|
||||||
|
## Target selector
|
||||||
|
- Select resources with name matching `name*`
|
||||||
|
```yaml
|
||||||
|
target:
|
||||||
|
name: name*
|
||||||
|
```
|
||||||
|
- Select all Deployment resources
|
||||||
|
```yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
```
|
||||||
|
- Select resources matching label `app=hello`
|
||||||
|
```yaml
|
||||||
|
target:
|
||||||
|
labelSelector: app=hello
|
||||||
|
```
|
||||||
|
- Select resources matching annotation `app=hello`
|
||||||
|
```yaml
|
||||||
|
target:
|
||||||
|
annotationSelector: app=hello
|
||||||
|
```
|
||||||
|
- Select all Deployment resources matching label `app=hello`
|
||||||
|
```yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
labelSelector: app=hello
|
||||||
|
```
|
||||||
14
go.mod
14
go.mod
@@ -6,10 +6,16 @@ require (
|
|||||||
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
|
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||||
github.com/go-openapi/spec v0.19.2
|
github.com/go-openapi/spec v0.19.2
|
||||||
|
github.com/gogo/protobuf v1.2.1 // indirect
|
||||||
github.com/golang/protobuf v1.3.1 // indirect
|
github.com/golang/protobuf v1.3.1 // indirect
|
||||||
|
github.com/google/gofuzz v1.0.0 // indirect
|
||||||
github.com/googleapis/gnostic v0.3.0 // indirect
|
github.com/googleapis/gnostic v0.3.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.6 // indirect
|
||||||
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481 // indirect
|
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481 // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||||
|
github.com/onsi/gomega v1.5.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/spf13/cobra v0.0.2
|
github.com/spf13/cobra v0.0.2
|
||||||
github.com/spf13/pflag v1.0.3
|
github.com/spf13/pflag v1.0.3
|
||||||
@@ -17,10 +23,10 @@ require (
|
|||||||
golang.org/x/sys v0.0.0-20190621203818-d432491b9138 // indirect
|
golang.org/x/sys v0.0.0-20190621203818-d432491b9138 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
gopkg.in/yaml.v2 v2.2.2
|
||||||
k8s.io/api v0.0.0-20190809220925-3ab596449d6f
|
k8s.io/api v0.0.0-20190313235455-40a48860b5ab
|
||||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010
|
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1
|
||||||
k8s.io/client-go v0.0.0-20190812221009-4f902818859a
|
k8s.io/client-go v11.0.0+incompatible
|
||||||
k8s.io/klog v0.3.3 // indirect
|
k8s.io/klog v0.3.3 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058
|
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208
|
||||||
sigs.k8s.io/yaml v1.1.0
|
sigs.k8s.io/yaml v1.1.0
|
||||||
)
|
)
|
||||||
|
|||||||
48
go.sum
48
go.sum
@@ -1,5 +1,3 @@
|
|||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
@@ -12,13 +10,9 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
|
github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
|
||||||
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
@@ -38,40 +32,26 @@ github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88d
|
|||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
|
||||||
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
|
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
|
||||||
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
|
||||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 h1:/UewZcckqhvnnS0C6r3Sher2hSEbVmM6Ogpcjen08+Y=
|
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 h1:/UewZcckqhvnnS0C6r3Sher2hSEbVmM6Ogpcjen08+Y=
|
||||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -83,16 +63,13 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
|
|||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481 h1:IaSjLMT6WvkoZZjspGxy3rdaTEmWLoRm49WbtVUi9sA=
|
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481 h1:IaSjLMT6WvkoZZjspGxy3rdaTEmWLoRm49WbtVUi9sA=
|
||||||
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da h1:ZQGIPjr1iTtUPXZFk8WShqb5G+Qg65VHFLtSvmHh+Mw=
|
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da h1:ZQGIPjr1iTtUPXZFk8WShqb5G+Qg65VHFLtSvmHh+Mw=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||||
@@ -100,13 +77,11 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
|
||||||
github.com/spf13/cobra v0.0.2 h1:NfkwRbgViGoyjBKsLI0QMDcuMnhM+SBg3T0cGfpvKDE=
|
github.com/spf13/cobra v0.0.2 h1:NfkwRbgViGoyjBKsLI0QMDcuMnhM+SBg3T0cGfpvKDE=
|
||||||
github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
@@ -117,27 +92,21 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
|||||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -149,22 +118,17 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
@@ -175,27 +139,17 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
k8s.io/api v0.0.0-20190313235455-40a48860b5ab h1:DG9A67baNpoeweOy2spF1OWHhnVY5KR7/Ek/+U1lVZc=
|
k8s.io/api v0.0.0-20190313235455-40a48860b5ab h1:DG9A67baNpoeweOy2spF1OWHhnVY5KR7/Ek/+U1lVZc=
|
||||||
k8s.io/api v0.0.0-20190313235455-40a48860b5ab/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
k8s.io/api v0.0.0-20190313235455-40a48860b5ab/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
||||||
k8s.io/api v0.0.0-20190809220925-3ab596449d6f h1:Ica1a7bw1U7AKaTDYgumijQa95BxzapaG9F7g8h2bjs=
|
|
||||||
k8s.io/api v0.0.0-20190809220925-3ab596449d6f/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58=
|
|
||||||
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1 h1:IS7K02iBkQXpCeieSiyJjGoLSdVOv2DbPaWHJ+ZtgKg=
|
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1 h1:IS7K02iBkQXpCeieSiyJjGoLSdVOv2DbPaWHJ+ZtgKg=
|
||||||
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
|
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
|
||||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010 h1:pyoq062NftC1y/OcnbSvgolyZDJ8y4fmUPWMkdA6gfU=
|
|
||||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
|
|
||||||
k8s.io/client-go v0.0.0-20190812221009-4f902818859a h1:Q6MWhZhFJehn507QasOhePysGew/kq+cCeei+M9L1t8=
|
|
||||||
k8s.io/client-go v0.0.0-20190812221009-4f902818859a/go.mod h1:2rTYlEIRnJeJ+Y2va8HpkQBKyWjf+Uo3A8KVGcf+eMA=
|
|
||||||
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
|
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
|
||||||
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
|
||||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
|
||||||
k8s.io/klog v0.3.3 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c=
|
k8s.io/klog v0.3.3 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c=
|
||||||
k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
|
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
|
||||||
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
|
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
|
||||||
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058 h1:di3XCwddOR9cWBNpfgXaskhh6cgJuwcK54rvtwUaC10=
|
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||||
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
|
|
||||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
|
||||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ package kunstruct
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
@@ -65,6 +69,11 @@ func (fs *UnstructAdapter) GetGvk() gvk.Gvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetGvk set the Gvk of the object to the input Gvk
|
||||||
|
func (fs *UnstructAdapter) SetGvk(g gvk.Gvk) {
|
||||||
|
fs.SetGroupVersionKind(toSchemaGvk(g))
|
||||||
|
}
|
||||||
|
|
||||||
// Copy provides a copy behind an interface.
|
// Copy provides a copy behind an interface.
|
||||||
func (fs *UnstructAdapter) Copy() ifc.Kunstructured {
|
func (fs *UnstructAdapter) Copy() ifc.Kunstructured {
|
||||||
return &UnstructAdapter{*fs.DeepCopy()}
|
return &UnstructAdapter{*fs.DeepCopy()}
|
||||||
@@ -285,3 +294,63 @@ func (fs *UnstructAdapter) MatchesAnnotationSelector(selector string) (bool, err
|
|||||||
}
|
}
|
||||||
return s.Matches(labels.Set(fs.GetAnnotations())), nil
|
return s.Matches(labels.Set(fs.GetAnnotations())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *UnstructAdapter) Patch(patch ifc.Kunstructured) error {
|
||||||
|
versionedObj, err := scheme.Scheme.New(
|
||||||
|
toSchemaGvk(patch.GetGvk()))
|
||||||
|
merged := map[string]interface{}{}
|
||||||
|
saveName := fs.GetName()
|
||||||
|
switch {
|
||||||
|
case runtime.IsNotRegisteredError(err):
|
||||||
|
baseBytes, err := json.Marshal(fs.Map())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
patchBytes, err := json.Marshal(patch.Map())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mergedBytes, err := jsonpatch.MergePatch(baseBytes, patchBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(mergedBytes, &merged)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case err != nil:
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
// Use Strategic-Merge-Patch to handle types w/ schema
|
||||||
|
// TODO: Change this to use the new Merge package.
|
||||||
|
// Store the name of the target object, because this name may have been munged.
|
||||||
|
// Apply this name to the patched object.
|
||||||
|
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(
|
||||||
|
fs.Map(),
|
||||||
|
patch.Map(),
|
||||||
|
lookupPatchMeta)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.SetMap(merged)
|
||||||
|
if len(fs.Map()) != 0 {
|
||||||
|
// if the patch deletes the object
|
||||||
|
// don't reset the name
|
||||||
|
fs.SetName(saveName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// toSchemaGvk converts to a schema.GroupVersionKind.
|
||||||
|
func toSchemaGvk(x gvk.Gvk) schema.GroupVersionKind {
|
||||||
|
return schema.GroupVersionKind{
|
||||||
|
Group: x.Group,
|
||||||
|
Version: x.Version,
|
||||||
|
Kind: x.Kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer/patch"
|
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer/patch"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FactoryImpl makes patch transformer and name hash transformer
|
// FactoryImpl makes patch transformer and name hash transformer
|
||||||
@@ -18,9 +18,8 @@ func NewFactoryImpl() *FactoryImpl {
|
|||||||
return &FactoryImpl{}
|
return &FactoryImpl{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakePatchTransformer makes a new patch transformer
|
func (p *FactoryImpl) MergePatches(patches []*resource.Resource,
|
||||||
func (p *FactoryImpl) MakePatchTransformer(
|
rf *resource.Factory) (
|
||||||
slice []*resource.Resource,
|
resmap.ResMap, error) {
|
||||||
rf *resource.Factory) (transformers.Transformer, error) {
|
return patch.MergePatches(patches, rf)
|
||||||
return patch.NewTransformer(slice, rf)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ package patch
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
|
|
||||||
"github.com/evanphx/json-patch"
|
"github.com/evanphx/json-patch"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -40,7 +45,7 @@ func (jmp *jsonMergePatch) findConflict(
|
|||||||
if i == conflictingPatchIdx {
|
if i == conflictingPatchIdx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !patches[conflictingPatchIdx].OrgId().GvknEquals(patch.OrgId()) {
|
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conflict, err := mergepatch.HasConflicts(
|
conflict, err := mergepatch.HasConflicts(
|
||||||
@@ -100,7 +105,7 @@ func (smp *strategicMergePatch) findConflict(
|
|||||||
if i == conflictingPatchIdx {
|
if i == conflictingPatchIdx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !patches[conflictingPatchIdx].OrgId().GvknEquals(patch.OrgId()) {
|
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conflict, err := strategicpatch.MergingMapsHaveConflicts(
|
conflict, err := strategicpatch.MergingMapsHaveConflicts(
|
||||||
@@ -122,3 +127,64 @@ func (smp *strategicMergePatch) mergePatches(patch1, patch2 *resource.Resource)
|
|||||||
smp.lookupPatchMeta, patch1.Map(), patch2.Map())
|
smp.lookupPatchMeta, patch1.Map(), patch2.Map())
|
||||||
return smp.rf.FromMap(mergeJSONMap), err
|
return smp.rf.FromMap(mergeJSONMap), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mergePatches merge and index patches by OrgId.
|
||||||
|
// It errors out if there is conflict between patches.
|
||||||
|
func MergePatches(patches []*resource.Resource,
|
||||||
|
rf *resource.Factory) (resmap.ResMap, error) {
|
||||||
|
rc := resmap.New()
|
||||||
|
for ix, patch := range patches {
|
||||||
|
id := patch.OrgId()
|
||||||
|
existing := rc.GetMatchingResourcesByOriginalId(id.Equals)
|
||||||
|
if len(existing) == 0 {
|
||||||
|
rc.Append(patch)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(existing) > 1 {
|
||||||
|
return nil, fmt.Errorf("self conflict in patches")
|
||||||
|
}
|
||||||
|
|
||||||
|
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
|
||||||
|
if err != nil && !runtime.IsNotRegisteredError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var cd conflictDetector
|
||||||
|
if err != nil {
|
||||||
|
cd = newJMPConflictDetector(rf)
|
||||||
|
} else {
|
||||||
|
cd, err = newSMPConflictDetector(versionedObj, rf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conflict, err := cd.hasConflict(existing[0], patch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if conflict {
|
||||||
|
conflictingPatch, err := cd.findConflict(ix, patches)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"conflict between %#v and %#v",
|
||||||
|
conflictingPatch.Map(), patch.Map())
|
||||||
|
}
|
||||||
|
merged, err := cd.mergePatches(existing[0], patch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rc.Replace(merged)
|
||||||
|
}
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// toSchemaGvk converts to a schema.GroupVersionKind.
|
||||||
|
func toSchemaGvk(x gvk.Gvk) schema.GroupVersionKind {
|
||||||
|
return schema.GroupVersionKind{
|
||||||
|
Group: x.Group,
|
||||||
|
Version: x.Version,
|
||||||
|
Kind: x.Kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,156 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package patch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/evanphx/json-patch"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// transformer applies strategic merge patches.
|
|
||||||
type transformer struct {
|
|
||||||
patches []*resource.Resource
|
|
||||||
rf *resource.Factory
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ transformers.Transformer = &transformer{}
|
|
||||||
|
|
||||||
// NewTransformer constructs a strategic merge patch transformer.
|
|
||||||
func NewTransformer(
|
|
||||||
slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) {
|
|
||||||
if len(slice) == 0 {
|
|
||||||
return transformers.NewNoOpTransformer(), nil
|
|
||||||
}
|
|
||||||
return &transformer{patches: slice, rf: rf}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform apply the patches on top of the base resources.
|
|
||||||
// nolint:ineffassign
|
|
||||||
func (tf *transformer) Transform(m resmap.ResMap) error {
|
|
||||||
patches, err := tf.mergePatches()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, patch := range patches.Resources() {
|
|
||||||
target, err := m.GetById(patch.OrgId())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
merged := map[string]interface{}{}
|
|
||||||
versionedObj, err := scheme.Scheme.New(
|
|
||||||
toSchemaGvk(patch.OrgId().Gvk))
|
|
||||||
saveName := target.GetName()
|
|
||||||
switch {
|
|
||||||
case runtime.IsNotRegisteredError(err):
|
|
||||||
// Use JSON merge patch to handle types w/o schema
|
|
||||||
baseBytes, err := json.Marshal(target.Map())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
patchBytes, err := json.Marshal(patch.Map())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mergedBytes, err := jsonpatch.MergePatch(baseBytes, patchBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(mergedBytes, &merged)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case err != nil:
|
|
||||||
return err
|
|
||||||
default:
|
|
||||||
// Use Strategic-Merge-Patch to handle types w/ schema
|
|
||||||
// TODO: Change this to use the new Merge package.
|
|
||||||
// Store the name of the target object, because this name may have been munged.
|
|
||||||
// Apply this name to the patched object.
|
|
||||||
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(
|
|
||||||
target.Map(),
|
|
||||||
patch.Map(),
|
|
||||||
lookupPatchMeta)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target.SetMap(merged)
|
|
||||||
target.SetName(saveName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mergePatches merge and index patches by OrgId.
|
|
||||||
// It errors out if there is conflict between patches.
|
|
||||||
func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
|
||||||
rc := resmap.New()
|
|
||||||
for ix, patch := range tf.patches {
|
|
||||||
id := patch.OrgId()
|
|
||||||
existing := rc.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
|
||||||
if len(existing) == 0 {
|
|
||||||
rc.Append(patch)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(existing) > 1 {
|
|
||||||
return nil, fmt.Errorf("self conflict in patches")
|
|
||||||
}
|
|
||||||
|
|
||||||
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
|
|
||||||
if err != nil && !runtime.IsNotRegisteredError(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var cd conflictDetector
|
|
||||||
if err != nil {
|
|
||||||
cd = newJMPConflictDetector(tf.rf)
|
|
||||||
} else {
|
|
||||||
cd, err = newSMPConflictDetector(versionedObj, tf.rf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conflict, err := cd.hasConflict(existing[0], patch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if conflict {
|
|
||||||
conflictingPatch, err := cd.findConflict(ix, tf.patches)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"conflict between %#v and %#v",
|
|
||||||
conflictingPatch.Map(), patch.Map())
|
|
||||||
}
|
|
||||||
merged, err := cd.mergePatches(existing[0], patch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rc.Replace(merged)
|
|
||||||
}
|
|
||||||
return rc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// toSchemaGvk converts to a schema.GroupVersionKind.
|
|
||||||
func toSchemaGvk(x gvk.Gvk) schema.GroupVersionKind {
|
|
||||||
return schema.GroupVersionKind{
|
|
||||||
Group: x.Group,
|
|
||||||
Version: x.Version,
|
|
||||||
Kind: x.Kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,579 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package patch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rf = resource.NewFactory(
|
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
|
||||||
|
|
||||||
func TestOverlayRun(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(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{}{
|
|
||||||
"another-label": "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:latest",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "SOMEENV",
|
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(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",
|
|
||||||
"another-label": "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:latest",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "SOMEENV",
|
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(base, expected) {
|
|
||||||
err = expected.ErrorIfNotEqualLists(base)
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMultiplePatches(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:latest",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "SOMEENV",
|
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "ANOTHERENV",
|
|
||||||
"value": "HELLO",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "busybox",
|
|
||||||
"image": "busybox",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:latest",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "ANOTHERENV",
|
|
||||||
"value": "HELLO",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "SOMEENV",
|
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "busybox",
|
|
||||||
"image": "busybox",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(base, expected) {
|
|
||||||
err = expected.ErrorIfNotEqualLists(base)
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMultiplePatchesWithConflict(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:latest",
|
|
||||||
"env": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "SOMEENV",
|
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:1.7.9",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("did not get expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "conflict") {
|
|
||||||
t.Fatalf("expected error to contain %q but get %v", "conflict", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPatchesWithWrongNamespace(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
"namespace": "namespace1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
"namespace": "namespace2",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx:1.7.9",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("did not get expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "failed to find unique target for patch") {
|
|
||||||
t.Fatalf("expected error to contain %q but get %v", "failed to find target for patch", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoSchemaOverlayRun(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"B": nil,
|
|
||||||
"C": "Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"A": "X",
|
|
||||||
"C": "Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoSchemaMultiplePatches(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"B": nil,
|
|
||||||
"C": "Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"C": "Z",
|
|
||||||
"D": "W",
|
|
||||||
},
|
|
||||||
"baz": map[string]interface{}{
|
|
||||||
"hello": "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"A": "X",
|
|
||||||
"C": "Z",
|
|
||||||
"D": "W",
|
|
||||||
},
|
|
||||||
"baz": map[string]interface{}{
|
|
||||||
"hello": "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) {
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
patch := []*resource.Resource{
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"B": nil,
|
|
||||||
"C": "Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
|
||||||
"apiVersion": "example.com/v1",
|
|
||||||
"kind": "Foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "my-foo",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"bar": map[string]interface{}{
|
|
||||||
"C": "NOT_Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = lt.Transform(base)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("did not get expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "conflict") {
|
|
||||||
t.Fatalf("expected error to contain %q but get %v", "conflict", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -64,8 +64,14 @@ func (ra *ResAccumulator) GetTransformerConfig() *config.TransformerConfig {
|
|||||||
|
|
||||||
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
||||||
for _, v := range incoming {
|
for _, v := range incoming {
|
||||||
matched := ra.resMap.GetMatchingResourcesByOriginalId(
|
targetId := resid.NewResIdWithNamespace(v.ObjRef.GVK(), v.ObjRef.Name, v.ObjRef.Namespace)
|
||||||
resid.NewResId(v.ObjRef.GVK(), v.ObjRef.Name).GvknEquals)
|
idMatcher := targetId.GvknEquals
|
||||||
|
if targetId.Namespace != "" || !targetId.IsNamespaceableKind() {
|
||||||
|
// Preserve backward compatibility. An empty namespace means
|
||||||
|
// wildcard search on the namespace hence we still use GvknEquals
|
||||||
|
idMatcher = targetId.Equals
|
||||||
|
}
|
||||||
|
matched := ra.resMap.GetMatchingResourcesByOriginalId(idMatcher)
|
||||||
if len(matched) > 1 {
|
if len(matched) > 1 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"found %d resId matches for var %s "+
|
"found %d resId matches for var %s "+
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc/transformer"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
@@ -61,7 +60,7 @@ https://github.com/hashicorp/go-getter#url-format
|
|||||||
func NewCmdBuild(
|
func NewCmdBuild(
|
||||||
out io.Writer, fSys fs.FileSystem,
|
out io.Writer, fSys fs.FileSystem,
|
||||||
v ifc.Validator, rf *resmap.Factory,
|
v ifc.Validator, rf *resmap.Factory,
|
||||||
ptf transformer.Factory) *cobra.Command {
|
ptf resmap.PatchFactory) *cobra.Command {
|
||||||
var o Options
|
var o Options
|
||||||
|
|
||||||
pluginConfig := plugins.DefaultPluginConfig()
|
pluginConfig := plugins.DefaultPluginConfig()
|
||||||
@@ -115,7 +114,7 @@ func (o *Options) Validate(args []string) (err error) {
|
|||||||
// RunBuild runs build command.
|
// RunBuild runs build command.
|
||||||
func (o *Options) RunBuild(
|
func (o *Options) RunBuild(
|
||||||
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
||||||
rf *resmap.Factory, ptf transformer.Factory,
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||||
pl *plugins.Loader) error {
|
pl *plugins.Loader) error {
|
||||||
ldr, err := loader.NewLoader(
|
ldr, err := loader.NewLoader(
|
||||||
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
||||||
@@ -136,7 +135,7 @@ func (o *Options) RunBuild(
|
|||||||
|
|
||||||
func (o *Options) RunBuildPrune(
|
func (o *Options) RunBuildPrune(
|
||||||
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
||||||
rf *resmap.Factory, ptf transformer.Factory,
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||||
pl *plugins.Loader) error {
|
pl *plugins.Loader) error {
|
||||||
ldr, err := loader.NewLoader(
|
ldr, err := loader.NewLoader(
|
||||||
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
||||||
@@ -180,7 +179,7 @@ func (o *Options) emitResources(
|
|||||||
|
|
||||||
func NewCmdBuildPrune(
|
func NewCmdBuildPrune(
|
||||||
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
||||||
rf *resmap.Factory, ptf transformer.Factory,
|
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||||
pl *plugins.Loader) *cobra.Command {
|
pl *plugins.Loader) *cobra.Command {
|
||||||
var o Options
|
var o Options
|
||||||
|
|
||||||
@@ -202,7 +201,7 @@ func NewCmdBuildPrune(
|
|||||||
|
|
||||||
func writeIndividualFiles(
|
func writeIndividualFiles(
|
||||||
fSys fs.FileSystem, folderPath string, m resmap.ResMap) error {
|
fSys fs.FileSystem, folderPath string, m resmap.ResMap) error {
|
||||||
byNamespace := m.GroupedByNamespace()
|
byNamespace := m.GroupedByCurrentNamespace()
|
||||||
for namespace, resList := range byNamespace {
|
for namespace, resList := range byNamespace {
|
||||||
for _, res := range resList {
|
for _, res := range resList {
|
||||||
fName := fileName(res)
|
fName := fileName(res)
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ See https://sigs.k8s.io/kustomize
|
|||||||
}
|
}
|
||||||
|
|
||||||
uf := kunstruct.NewKunstructuredFactoryImpl()
|
uf := kunstruct.NewKunstructuredFactoryImpl()
|
||||||
rf := resmap.NewFactory(resource.NewFactory(uf))
|
pf := transformer.NewFactoryImpl()
|
||||||
|
rf := resmap.NewFactory(resource.NewFactory(uf), pf)
|
||||||
v := validator.NewKustValidator()
|
v := validator.NewKustValidator()
|
||||||
c.AddCommand(
|
c.AddCommand(
|
||||||
build.NewCmdBuild(
|
build.NewCmdBuild(
|
||||||
stdOut, fSys, v,
|
stdOut, fSys, v,
|
||||||
rf, transformer.NewFactoryImpl()),
|
rf, pf),
|
||||||
edit.NewCmdEdit(fSys, v, uf),
|
edit.NewCmdEdit(fSys, v, uf),
|
||||||
misc.NewCmdConfig(fSys),
|
misc.NewCmdConfig(fSys),
|
||||||
misc.NewCmdVersion(stdOut),
|
misc.NewCmdVersion(stdOut),
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func determineFieldOrder() []string {
|
|||||||
"CommonAnnotations",
|
"CommonAnnotations",
|
||||||
"PatchesStrategicMerge",
|
"PatchesStrategicMerge",
|
||||||
"PatchesJson6902",
|
"PatchesJson6902",
|
||||||
|
"Patches",
|
||||||
"ConfigMapGenerator",
|
"ConfigMapGenerator",
|
||||||
"SecretGenerator",
|
"SecretGenerator",
|
||||||
"GeneratorOptions",
|
"GeneratorOptions",
|
||||||
@@ -73,9 +74,7 @@ func determineFieldOrder() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add deprecated fields here.
|
// Add deprecated fields here.
|
||||||
deprecated := map[string]bool{
|
deprecated := map[string]bool{}
|
||||||
"Patches": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account for the inlined TypeMeta fields.
|
// Account for the inlined TypeMeta fields.
|
||||||
var result []string
|
var result []string
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ func TestFieldOrder(t *testing.T) {
|
|||||||
"CommonAnnotations",
|
"CommonAnnotations",
|
||||||
"PatchesStrategicMerge",
|
"PatchesStrategicMerge",
|
||||||
"PatchesJson6902",
|
"PatchesJson6902",
|
||||||
|
"Patches",
|
||||||
"ConfigMapGenerator",
|
"ConfigMapGenerator",
|
||||||
"SecretGenerator",
|
"SecretGenerator",
|
||||||
"GeneratorOptions",
|
"GeneratorOptions",
|
||||||
@@ -264,3 +265,85 @@ generatorOptions:
|
|||||||
string(expected), string(bytes))
|
string(expected), string(bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFixPatchesField(t *testing.T) {
|
||||||
|
kustomizationContentWithComments := []byte(`
|
||||||
|
patches:
|
||||||
|
- patch1.yaml
|
||||||
|
- patch2.yaml
|
||||||
|
`)
|
||||||
|
|
||||||
|
expected := []byte(`
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- patch1.yaml
|
||||||
|
- patch2.yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
`)
|
||||||
|
fSys := fs.MakeFakeFS()
|
||||||
|
fSys.WriteTestKustomizationWith(kustomizationContentWithComments)
|
||||||
|
mf, err := NewKustomizationFile(fSys)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kustomization, err := mf.Read()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
if err = mf.Write(kustomization); err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
bytes, _ := fSys.ReadFile(mf.path)
|
||||||
|
|
||||||
|
if string(expected) != string(bytes) {
|
||||||
|
t.Fatalf(
|
||||||
|
"expected =\n%s\n\nactual =\n%s\n",
|
||||||
|
string(expected), string(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFixPatchesFieldForExtendedPatch(t *testing.T) {
|
||||||
|
kustomizationContentWithComments := []byte(`
|
||||||
|
patches:
|
||||||
|
- path: patch1.yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
- path: patch2.yaml
|
||||||
|
target:
|
||||||
|
kind: Service
|
||||||
|
`)
|
||||||
|
|
||||||
|
expected := []byte(`
|
||||||
|
patches:
|
||||||
|
- path: patch1.yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
- path: patch2.yaml
|
||||||
|
target:
|
||||||
|
kind: Service
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
`)
|
||||||
|
fSys := fs.MakeFakeFS()
|
||||||
|
fSys.WriteTestKustomizationWith(kustomizationContentWithComments)
|
||||||
|
mf, err := NewKustomizationFile(fSys)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kustomization, err := mf.Read()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
if err = mf.Write(kustomization); err != nil {
|
||||||
|
t.Fatalf("Unexpected Error: %v", err)
|
||||||
|
}
|
||||||
|
bytes, _ := fSys.ReadFile(mf.path)
|
||||||
|
|
||||||
|
if string(expected) != string(bytes) {
|
||||||
|
t.Fatalf(
|
||||||
|
"expected =\n%s\n\nactual =\n%s\n",
|
||||||
|
string(expected), string(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ func (x Gvk) Equals(o Gvk) bool {
|
|||||||
// In some cases order just specified to provide determinism.
|
// In some cases order just specified to provide determinism.
|
||||||
var orderFirst = []string{
|
var orderFirst = []string{
|
||||||
"Namespace",
|
"Namespace",
|
||||||
|
"ResourceQuota",
|
||||||
"StorageClass",
|
"StorageClass",
|
||||||
"CustomResourceDefinition",
|
"CustomResourceDefinition",
|
||||||
"MutatingWebhookConfiguration",
|
"MutatingWebhookConfiguration",
|
||||||
|
|||||||
@@ -54,15 +54,18 @@ type Kunstructured interface {
|
|||||||
MarshalJSON() ([]byte, error)
|
MarshalJSON() ([]byte, error)
|
||||||
UnmarshalJSON([]byte) error
|
UnmarshalJSON([]byte) error
|
||||||
GetGvk() gvk.Gvk
|
GetGvk() gvk.Gvk
|
||||||
|
SetGvk(gvk.Gvk)
|
||||||
GetKind() string
|
GetKind() string
|
||||||
GetName() string
|
GetName() string
|
||||||
SetName(string)
|
SetName(string)
|
||||||
|
SetNamespace(string)
|
||||||
GetLabels() map[string]string
|
GetLabels() map[string]string
|
||||||
SetLabels(map[string]string)
|
SetLabels(map[string]string)
|
||||||
GetAnnotations() map[string]string
|
GetAnnotations() map[string]string
|
||||||
SetAnnotations(map[string]string)
|
SetAnnotations(map[string]string)
|
||||||
MatchesLabelSelector(selector string) (bool, error)
|
MatchesLabelSelector(selector string) (bool, error)
|
||||||
MatchesAnnotationSelector(selector string) (bool, error)
|
MatchesAnnotationSelector(selector string) (bool, error)
|
||||||
|
Patch(Kunstructured) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// KunstructuredFactory makes instances of Kunstructured.
|
// KunstructuredFactory makes instances of Kunstructured.
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
/// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Package patch holds miscellaneous interfaces used by kustomize.
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Factory makes transformers that require k8sdeps.
|
|
||||||
type Factory interface {
|
|
||||||
MakePatchTransformer(
|
|
||||||
slice []*resource.Resource,
|
|
||||||
rf *resource.Factory) (transformers.Transformer, error)
|
|
||||||
}
|
|
||||||
@@ -49,7 +49,7 @@ func NewKustTestHarnessFull(
|
|||||||
t *testing.T, path string,
|
t *testing.T, path string,
|
||||||
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
|
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
|
||||||
rf := resmap.NewFactory(resource.NewFactory(
|
rf := resmap.NewFactory(resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl()))
|
kunstruct.NewKunstructuredFactoryImpl()), transformer.NewFactoryImpl())
|
||||||
return &KustTestHarness{
|
return &KustTestHarness{
|
||||||
t: t,
|
t: t,
|
||||||
rf: rf,
|
rf: rf,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestExecPluginConfig(t *testing.T) {
|
|||||||
path := "/app"
|
path := "/app"
|
||||||
rf := resmap.NewFactory(
|
rf := resmap.NewFactory(
|
||||||
resource.NewFactory(
|
resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl()))
|
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||||
ldr := loadertest.NewFakeLoader(path)
|
ldr := loadertest.NewFakeLoader(path)
|
||||||
pluginConfig := rf.RF().FromMap(
|
pluginConfig := rf.RF().FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/v3/internal/loadertest"
|
"sigs.k8s.io/kustomize/v3/internal/loadertest"
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
||||||
. "sigs.k8s.io/kustomize/v3/pkg/plugins"
|
. "sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
)
|
)
|
||||||
@@ -41,7 +42,7 @@ port: "12345"
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestLoader(t *testing.T) {
|
func TestLoader(t *testing.T) {
|
||||||
tc := NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -50,7 +51,7 @@ func TestLoader(t *testing.T) {
|
|||||||
"someteam.example.com", "v1", "SomeServiceGenerator")
|
"someteam.example.com", "v1", "SomeServiceGenerator")
|
||||||
|
|
||||||
rmF := resmap.NewFactory(resource.NewFactory(
|
rmF := resmap.NewFactory(resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl()))
|
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||||
|
|
||||||
l := NewLoader(ActivePluginConfig(), rmF)
|
l := NewLoader(ActivePluginConfig(), rmF)
|
||||||
if l == nil {
|
if l == nil {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package plugins
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -12,13 +12,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvForTest manages the plugin test environment.
|
// EnvForTest manages the plugin test environment.
|
||||||
// It sets/resets XDG_CONFIG_HOME, makes/removes a temp objRoot.
|
// It sets/resets XDG_CONFIG_HOME, makes/removes a temp objRoot.
|
||||||
type EnvForTest struct {
|
type EnvForTest struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
compiler *Compiler
|
compiler *plugins.Compiler
|
||||||
workDir string
|
workDir string
|
||||||
oldXdg string
|
oldXdg string
|
||||||
wasSet bool
|
wasSet bool
|
||||||
@@ -61,7 +62,7 @@ func (x *EnvForTest) BuildExecPlugin(g, v, k string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EnvForTest) makeCompiler() *Compiler {
|
func (x *EnvForTest) makeCompiler() *plugins.Compiler {
|
||||||
// The plugin loader wants to find object code under
|
// The plugin loader wants to find object code under
|
||||||
// $XDG_CONFIG_HOME/kustomize/plugins
|
// $XDG_CONFIG_HOME/kustomize/plugins
|
||||||
// and the compiler writes object code to
|
// and the compiler writes object code to
|
||||||
@@ -73,11 +74,11 @@ func (x *EnvForTest) makeCompiler() *Compiler {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
x.t.Error(err)
|
x.t.Error(err)
|
||||||
}
|
}
|
||||||
srcRoot, err := DefaultSrcRoot()
|
srcRoot, err := plugins.DefaultSrcRoot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
x.t.Error(err)
|
x.t.Error(err)
|
||||||
}
|
}
|
||||||
return NewCompiler(srcRoot, objRoot)
|
return plugins.NewCompiler(srcRoot, objRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EnvForTest) createWorkDir() {
|
func (x *EnvForTest) createWorkDir() {
|
||||||
@@ -14,11 +14,12 @@ import (
|
|||||||
// Factory makes instances of ResMap.
|
// Factory makes instances of ResMap.
|
||||||
type Factory struct {
|
type Factory struct {
|
||||||
resF *resource.Factory
|
resF *resource.Factory
|
||||||
|
tf PatchFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFactory returns a new resmap.Factory.
|
// NewFactory returns a new resmap.Factory.
|
||||||
func NewFactory(rf *resource.Factory) *Factory {
|
func NewFactory(rf *resource.Factory, tf PatchFactory) *Factory {
|
||||||
return &Factory{resF: rf}
|
return &Factory{resF: rf, tf: tf}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RF returns a resource.Factory.
|
// RF returns a resource.Factory.
|
||||||
@@ -118,6 +119,11 @@ func (rmF *Factory) FromSecretArgs(
|
|||||||
return rmF.FromResource(res), nil
|
return rmF.FromResource(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rmF *Factory) MergePatches(patches []*resource.Resource) (
|
||||||
|
ResMap, error) {
|
||||||
|
return rmF.tf.MergePatches(patches, rmF.resF)
|
||||||
|
}
|
||||||
|
|
||||||
func newResMapFromResourceSlice(resources []*resource.Resource) (ResMap, error) {
|
func newResMapFromResourceSlice(resources []*resource.Resource) (ResMap, error) {
|
||||||
result := New()
|
result := New()
|
||||||
for _, res := range resources {
|
for _, res := range resources {
|
||||||
|
|||||||
15
pkg/resmap/patchfactory.go
Normal file
15
pkg/resmap/patchfactory.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package patch holds miscellaneous interfaces used by kustomize.
|
||||||
|
package resmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PatchFactory makes transformers that require k8sdeps.
|
||||||
|
type PatchFactory interface {
|
||||||
|
MergePatches(patches []*resource.Resource,
|
||||||
|
rf *resource.Factory) (ResMap, error)
|
||||||
|
}
|
||||||
@@ -112,13 +112,18 @@ type ResMap interface {
|
|||||||
// match.
|
// match.
|
||||||
GetById(resid.ResId) (*resource.Resource, error)
|
GetById(resid.ResId) (*resource.Resource, error)
|
||||||
|
|
||||||
// GroupedByNamespace returns a map of namespace
|
// GroupedByCurrentNamespace returns a map of namespace
|
||||||
// to a slice of *Resource in that namespace.
|
// to a slice of *Resource in that namespace.
|
||||||
// Resources for whom IsNamespaceableKind is false are
|
// Resources for whom IsNamespaceableKind is false are
|
||||||
// are not included at all (see NonNamespaceable).
|
// are not included at all (see NonNamespaceable).
|
||||||
// Resources with an empty namespace are placed
|
// Resources with an empty namespace are placed
|
||||||
// in the resid.DefaultNamespace entry.
|
// in the resid.DefaultNamespace entry.
|
||||||
GroupedByNamespace() map[string][]*resource.Resource
|
GroupedByCurrentNamespace() map[string][]*resource.Resource
|
||||||
|
|
||||||
|
// GroupByOrginalNamespace performs as GroupByNamespace
|
||||||
|
// but use the original namespace instead of the current
|
||||||
|
// one to perform the grouping.
|
||||||
|
GroupedByOriginalNamespace() map[string][]*resource.Resource
|
||||||
|
|
||||||
// NonNamespaceable returns a slice of resources that
|
// NonNamespaceable returns a slice of resources that
|
||||||
// cannot be placed in a namespace, e.g.
|
// cannot be placed in a namespace, e.g.
|
||||||
@@ -390,19 +395,19 @@ func demandOneMatch(
|
|||||||
return nil, fmt.Errorf("no matches for %sId %s", s, id)
|
return nil, fmt.Errorf("no matches for %sId %s", s, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupedByNamespace implements ResMap.GroupByNamespace
|
// GroupedByCurrentNamespace implements ResMap.GroupByCurrentNamespace
|
||||||
func (m *resWrangler) GroupedByNamespace() map[string][]*resource.Resource {
|
func (m *resWrangler) GroupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||||
items := m.groupedByNamespace()
|
items := m.groupedByCurrentNamespace()
|
||||||
delete(items, resid.TotallyNotANamespace)
|
delete(items, resid.TotallyNotANamespace)
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonNamespaceable implements ResMap.NonNamespaceable
|
// NonNamespaceable implements ResMap.NonNamespaceable
|
||||||
func (m *resWrangler) NonNamespaceable() []*resource.Resource {
|
func (m *resWrangler) NonNamespaceable() []*resource.Resource {
|
||||||
return m.groupedByNamespace()[resid.TotallyNotANamespace]
|
return m.groupedByCurrentNamespace()[resid.TotallyNotANamespace]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *resWrangler) groupedByNamespace() map[string][]*resource.Resource {
|
func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||||
byNamespace := make(map[string][]*resource.Resource)
|
byNamespace := make(map[string][]*resource.Resource)
|
||||||
for _, res := range m.rList {
|
for _, res := range m.rList {
|
||||||
namespace := res.CurId().EffectiveNamespace()
|
namespace := res.CurId().EffectiveNamespace()
|
||||||
@@ -414,6 +419,25 @@ func (m *resWrangler) groupedByNamespace() map[string][]*resource.Resource {
|
|||||||
return byNamespace
|
return byNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupedByNamespace implements ResMap.GroupByOrginalNamespace
|
||||||
|
func (m *resWrangler) GroupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||||
|
items := m.groupedByOriginalNamespace()
|
||||||
|
delete(items, resid.TotallyNotANamespace)
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *resWrangler) groupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||||
|
byNamespace := make(map[string][]*resource.Resource)
|
||||||
|
for _, res := range m.rList {
|
||||||
|
namespace := res.OrgId().EffectiveNamespace()
|
||||||
|
if _, found := byNamespace[namespace]; !found {
|
||||||
|
byNamespace[namespace] = []*resource.Resource{}
|
||||||
|
}
|
||||||
|
byNamespace[namespace] = append(byNamespace[namespace], res)
|
||||||
|
}
|
||||||
|
return byNamespace
|
||||||
|
}
|
||||||
|
|
||||||
// AsYaml implements ResMap.
|
// AsYaml implements ResMap.
|
||||||
func (m *resWrangler) AsYaml() ([]byte, error) {
|
func (m *resWrangler) AsYaml() ([]byte, error) {
|
||||||
firstObj := true
|
firstObj := true
|
||||||
@@ -528,13 +552,17 @@ func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
|||||||
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
||||||
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||||
inputRes *resource.Resource) ResMap {
|
inputRes *resource.Resource) ResMap {
|
||||||
inputId := inputRes.OrgId()
|
|
||||||
if !inputId.IsNamespaceableKind() {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
result := New()
|
result := New()
|
||||||
|
inputId := inputRes.CurId()
|
||||||
|
isInputIdNamespaceable := inputId.IsNamespaceableKind()
|
||||||
|
rctxm := inputRes.PrefixesSuffixesEquals
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if !r.OrgId().IsNamespaceableKind() || inputRes.InSameFuzzyNamespace(r) {
|
// Need to match more accuratly both at the time of selection and transformation.
|
||||||
|
// OutmostPrefixSuffixEquals is not accurate enough since it is only using
|
||||||
|
// the outer most suffix and the last prefix. Use PrefixedSuffixesEquals instead.
|
||||||
|
resId := r.CurId()
|
||||||
|
if (!isInputIdNamespaceable || !resId.IsNamespaceableKind() || resId.IsNsEquals(inputId)) &&
|
||||||
|
r.InSameKustomizeCtx(rctxm) {
|
||||||
err := result.Append(r)
|
err := result.Append(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
var rf = resource.NewFactory(
|
var rf = resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
var rmF = NewFactory(rf)
|
var rmF = NewFactory(rf, nil)
|
||||||
|
|
||||||
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
|
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
|
||||||
err := w.Append(r)
|
err := w.Append(r)
|
||||||
@@ -356,7 +356,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
|||||||
r4 := rf.FromMap(
|
r4 := rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "Deployment",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "charlie",
|
"name": "charlie",
|
||||||
"namespace": "happy",
|
"namespace": "happy",
|
||||||
@@ -365,7 +365,7 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
|||||||
r5 := rf.FromMap(
|
r5 := rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Deployment",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "charlie",
|
"name": "charlie",
|
||||||
"namespace": "happy",
|
"namespace": "happy",
|
||||||
@@ -408,12 +408,12 @@ func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
|||||||
"happy namespace no prefix": {
|
"happy namespace no prefix": {
|
||||||
filter: r3,
|
filter: r3,
|
||||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
AddR(r3).AddR(r4).AddR(r7).ResMap(),
|
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||||
},
|
},
|
||||||
"happy namespace with prefix": {
|
"happy namespace with prefix": {
|
||||||
filter: r5,
|
filter: r5,
|
||||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||||
},
|
},
|
||||||
"cluster level": {
|
"cluster level": {
|
||||||
filter: r7,
|
filter: r7,
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ func (rm *rmBuilder) AddWithNs(ns string, m map[string]interface{}) *rmBuilder {
|
|||||||
return rm
|
return rm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rm *rmBuilder) AddWithNsAndName(ns string, n string, m map[string]interface{}) *rmBuilder {
|
||||||
|
err := rm.m.Append(rm.rf.FromMapWithNamespaceAndName(ns, n, m))
|
||||||
|
if err != nil {
|
||||||
|
rm.t.Fatalf("test setup failure: %v", err)
|
||||||
|
}
|
||||||
|
return rm
|
||||||
|
}
|
||||||
|
|
||||||
func (rm *rmBuilder) ReplaceResource(m map[string]interface{}) *rmBuilder {
|
func (rm *rmBuilder) ReplaceResource(m map[string]interface{}) *rmBuilder {
|
||||||
r := rm.rf.FromMap(m)
|
r := rm.rf.FromMap(m)
|
||||||
_, err := rm.m.Replace(r)
|
_, err := rm.m.Replace(r)
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ func (rf *Factory) FromMapWithNamespace(n string, m map[string]interface{}) *Res
|
|||||||
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(n)
|
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromMapWithNamespaceAndName returns a new instance with the given "original" namespace.
|
||||||
|
func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource {
|
||||||
|
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(ns).setOriginalName(n)
|
||||||
|
}
|
||||||
|
|
||||||
// FromMapAndOption returns a new instance of Resource with given options.
|
// FromMapAndOption returns a new instance of Resource with given options.
|
||||||
func (rf *Factory) FromMapAndOption(
|
func (rf *Factory) FromMapAndOption(
|
||||||
m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *Resource {
|
m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *Resource {
|
||||||
|
|||||||
@@ -27,6 +27,22 @@ type Resource struct {
|
|||||||
nameSuffixes []string
|
nameSuffixes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResCtx is an interface describing the contextual added
|
||||||
|
// kept kustomize in the context of each Resource object.
|
||||||
|
// Currently mainly the name prefix and name suffix are added.
|
||||||
|
type ResCtx interface {
|
||||||
|
AddNamePrefix(p string)
|
||||||
|
AddNameSuffix(s string)
|
||||||
|
GetOutermostNamePrefix() string
|
||||||
|
GetOutermostNameSuffix() string
|
||||||
|
GetNamePrefixes() []string
|
||||||
|
GetNameSuffixes() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResCtxMatcher returns true if two Resources are being
|
||||||
|
// modified in the same kustomize context.
|
||||||
|
type ResCtxMatcher func(ResCtx) bool
|
||||||
|
|
||||||
// DeepCopy returns a new copy of resource
|
// DeepCopy returns a new copy of resource
|
||||||
func (r *Resource) DeepCopy() *Resource {
|
func (r *Resource) DeepCopy() *Resource {
|
||||||
rc := &Resource{
|
rc := &Resource{
|
||||||
@@ -42,6 +58,7 @@ func (r *Resource) Replace(other *Resource) {
|
|||||||
r.SetAnnotations(
|
r.SetAnnotations(
|
||||||
mergeStringMaps(other.GetAnnotations(), r.GetAnnotations()))
|
mergeStringMaps(other.GetAnnotations(), r.GetAnnotations()))
|
||||||
r.SetName(other.GetName())
|
r.SetName(other.GetName())
|
||||||
|
r.SetNamespace(other.GetNamespace())
|
||||||
r.copyOtherFields(other)
|
r.copyOtherFields(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,14 +120,17 @@ func copyStringSlice(s []string) []string {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx AddNamePrefix
|
||||||
func (r *Resource) AddNamePrefix(p string) {
|
func (r *Resource) AddNamePrefix(p string) {
|
||||||
r.namePrefixes = append(r.namePrefixes, p)
|
r.namePrefixes = append(r.namePrefixes, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx AddNameSuffix
|
||||||
func (r *Resource) AddNameSuffix(s string) {
|
func (r *Resource) AddNameSuffix(s string) {
|
||||||
r.nameSuffixes = append(r.nameSuffixes, s)
|
r.nameSuffixes = append(r.nameSuffixes, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx GetOutermostNamePrefix
|
||||||
func (r *Resource) GetOutermostNamePrefix() string {
|
func (r *Resource) GetOutermostNamePrefix() string {
|
||||||
if len(r.namePrefixes) == 0 {
|
if len(r.namePrefixes) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -118,6 +138,7 @@ func (r *Resource) GetOutermostNamePrefix() string {
|
|||||||
return r.namePrefixes[len(r.namePrefixes)-1]
|
return r.namePrefixes[len(r.namePrefixes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx GetOutermostNameSuffix
|
||||||
func (r *Resource) GetOutermostNameSuffix() string {
|
func (r *Resource) GetOutermostNameSuffix() string {
|
||||||
if len(r.nameSuffixes) == 0 {
|
if len(r.nameSuffixes) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -125,10 +146,51 @@ func (r *Resource) GetOutermostNameSuffix() string {
|
|||||||
return r.nameSuffixes[len(r.nameSuffixes)-1]
|
return r.nameSuffixes[len(r.nameSuffixes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) InSameFuzzyNamespace(o *Resource) bool {
|
func sameBeginningSubarray(a, b []string) bool {
|
||||||
return r.GetNamespace() == o.GetNamespace() &&
|
maxlen := len(b)
|
||||||
r.GetOutermostNamePrefix() == o.GetOutermostNamePrefix() &&
|
if len(a) < len(b) {
|
||||||
r.GetOutermostNameSuffix() == o.GetOutermostNameSuffix()
|
maxlen = len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxlen == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range a[0 : maxlen-1] {
|
||||||
|
if v != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx GetNamePrefixes
|
||||||
|
func (r *Resource) GetNamePrefixes() []string {
|
||||||
|
return r.namePrefixes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements ResCtx GetNameSuffixes
|
||||||
|
func (r *Resource) GetNameSuffixes() []string {
|
||||||
|
return r.nameSuffixes
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutermostPrefixSuffixEquals returns true if both resources
|
||||||
|
// outer suffix and prefix matches.
|
||||||
|
func (r *Resource) OutermostPrefixSuffixEquals(o ResCtx) bool {
|
||||||
|
return (r.GetOutermostNamePrefix() == o.GetOutermostNamePrefix()) && (r.GetOutermostNameSuffix() == o.GetOutermostNameSuffix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrefixesSuffixesEquals is conceptually doing the same task
|
||||||
|
// as OutermostPrefixSuffix but performs a deeper comparison
|
||||||
|
// of the the list of suffix and prefix.
|
||||||
|
func (r *Resource) PrefixesSuffixesEquals(o ResCtx) bool {
|
||||||
|
return sameBeginningSubarray(r.GetNamePrefixes(), o.GetNamePrefixes()) && sameBeginningSubarray(r.GetNameSuffixes(), o.GetNameSuffixes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is used to compute if a referrer could potentially be impacted
|
||||||
|
// by the change of name of a referral.
|
||||||
|
func (r *Resource) InSameKustomizeCtx(rctxm ResCtxMatcher) bool {
|
||||||
|
return rctxm(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) GetOriginalName() string {
|
func (r *Resource) GetOriginalName() string {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
package target_test
|
package target_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is an example of using a helm chart as a base,
|
// This is an example of using a helm chart as a base,
|
||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
// TODO: Download and inflate the chart, and check that
|
// TODO: Download and inflate the chart, and check that
|
||||||
// in for the test.
|
// in for the test.
|
||||||
func TestChartInflatorPlugin(t *testing.T) {
|
func TestChartInflatorPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
const patchAddProbe = `
|
const patchAddProbe = `
|
||||||
@@ -340,7 +340,7 @@ patchesStrategicMerge:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue1251_Plugins_ProdVsDev(t *testing.T) {
|
func TestIssue1251_Plugins_ProdVsDev(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -380,7 +380,7 @@ transformers:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue1251_Plugins_Local(t *testing.T) {
|
func TestIssue1251_Plugins_Local(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -430,7 +430,7 @@ jsonOp: '%s'
|
|||||||
|
|
||||||
// Remote in the sense that they are bundled in a different kustomization.
|
// Remote in the sense that they are bundled in a different kustomization.
|
||||||
func TestIssue1251_Plugins_Bundled(t *testing.T) {
|
func TestIssue1251_Plugins_Bundled(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
1248
pkg/target/extendedpatch_test.go
Normal file
1248
pkg/target/extendedpatch_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/accumulator"
|
"sigs.k8s.io/kustomize/v3/pkg/accumulator"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc/transformer"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
@@ -30,7 +29,7 @@ type KustTarget struct {
|
|||||||
kustomization *types.Kustomization
|
kustomization *types.Kustomization
|
||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
rFactory *resmap.Factory
|
rFactory *resmap.Factory
|
||||||
tFactory transformer.Factory
|
tFactory resmap.PatchFactory
|
||||||
pLdr *plugins.Loader
|
pLdr *plugins.Loader
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ type KustTarget struct {
|
|||||||
func NewKustTarget(
|
func NewKustTarget(
|
||||||
ldr ifc.Loader,
|
ldr ifc.Loader,
|
||||||
rFactory *resmap.Factory,
|
rFactory *resmap.Factory,
|
||||||
tFactory transformer.Factory,
|
tFactory resmap.PatchFactory,
|
||||||
pLdr *plugins.Loader) (*KustTarget, error) {
|
pLdr *plugins.Loader) (*KustTarget, error) {
|
||||||
content, err := loadKustFile(ldr)
|
content, err := loadKustFile(ldr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -293,19 +292,7 @@ func (kt *KustTarget) configureExternalGenerators() ([]transformers.Generator, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
||||||
patches, err := kt.rFactory.RF().SliceFromPatches(
|
|
||||||
kt.ldr, kt.kustomization.PatchesStrategicMerge)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(
|
|
||||||
err, "reading strategic merge patches %v",
|
|
||||||
kt.kustomization.PatchesStrategicMerge)
|
|
||||||
}
|
|
||||||
var r []transformers.Transformer
|
var r []transformers.Transformer
|
||||||
t, err := kt.tFactory.MakePatchTransformer(patches, kt.rFactory.RF())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r = append(r, t)
|
|
||||||
tConfig := ra.GetTransformerConfig()
|
tConfig := ra.GetTransformerConfig()
|
||||||
lts, err := kt.configureBuiltinTransformers(tConfig)
|
lts, err := kt.configureBuiltinTransformers(tConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -317,7 +304,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r = append(r, lts...)
|
r = append(r, lts...)
|
||||||
t = transformers.NewMultiTransformer(r)
|
t := transformers.NewMultiTransformer(r)
|
||||||
return ra.Transform(t)
|
return ra.Transform(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ func (kt *KustTarget) configureBuiltinTransformers(
|
|||||||
// with tests:
|
// with tests:
|
||||||
// - patch SMP
|
// - patch SMP
|
||||||
configurators := []transformerConfigurator{
|
configurators := []transformerConfigurator{
|
||||||
|
kt.configureBuiltinPatchStrategicMergeTransformer,
|
||||||
|
kt.configureBuiltinPatchTransformer,
|
||||||
kt.configureBuiltinNamespaceTransformer,
|
kt.configureBuiltinNamespaceTransformer,
|
||||||
kt.configureBuiltinNameTransformer,
|
kt.configureBuiltinNameTransformer,
|
||||||
kt.configureBuiltinLabelTransformer,
|
kt.configureBuiltinLabelTransformer,
|
||||||
@@ -165,6 +167,52 @@ func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kt *KustTarget) configureBuiltinPatchStrategicMergeTransformer(
|
||||||
|
tConfig *config.TransformerConfig) (
|
||||||
|
result []transformers.Transformer, err error) {
|
||||||
|
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var c struct {
|
||||||
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
|
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
|
}
|
||||||
|
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||||
|
c.Patches = "" // Not implemented for kustomization file yet
|
||||||
|
p := builtin.NewPatchStrategicMergeTransformerPlugin()
|
||||||
|
err = kt.configureBuiltinPlugin(p, c, "patchStrategicMerge")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kt *KustTarget) configureBuiltinPatchTransformer(
|
||||||
|
tConfig *config.TransformerConfig) (
|
||||||
|
result []transformers.Transformer, err error) {
|
||||||
|
if len(kt.kustomization.Patches) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var c struct {
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
|
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
}
|
||||||
|
for _, patch := range kt.kustomization.Patches {
|
||||||
|
c.Target = patch.Target
|
||||||
|
c.Patch = patch.Patch
|
||||||
|
c.Path = patch.Path
|
||||||
|
p := builtin.NewPatchTransformerPlugin()
|
||||||
|
err = kt.configureBuiltinPlugin(p, c, "patch")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, p)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) configureBuiltinLabelTransformer(
|
func (kt *KustTarget) configureBuiltinLabelTransformer(
|
||||||
tConfig *config.TransformerConfig) (
|
tConfig *config.TransformerConfig) (
|
||||||
result []transformers.Transformer, err error) {
|
result []transformers.Transformer, err error) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package target_test
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -334,7 +333,10 @@ vars:
|
|||||||
t.Fatalf("unexpected size %d", len(vars))
|
t.Fatalf("unexpected size %d", len(vars))
|
||||||
}
|
}
|
||||||
for i := range vars[:2] {
|
for i := range vars[:2] {
|
||||||
if !reflect.DeepEqual(vars[i], someVars[i]) {
|
// By using Var.DeepEqual, we are protecting the code
|
||||||
|
// from a potential invocation of vars[i].ObjRef.GVK()
|
||||||
|
// during AccumulateTarget
|
||||||
|
if !vars[i].DeepEqual(someVars[i]) {
|
||||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,7 +389,10 @@ resources:
|
|||||||
t.Fatalf("expected 4 vars, got %d", len(vars))
|
t.Fatalf("expected 4 vars, got %d", len(vars))
|
||||||
}
|
}
|
||||||
for i := range vars {
|
for i := range vars {
|
||||||
if !reflect.DeepEqual(vars[i], someVars[i]) {
|
// By using Var.DeepEqual, we are protecting the code
|
||||||
|
// from a potential invocation of vars[i].ObjRef.GVK()
|
||||||
|
// during AccumulateTarget
|
||||||
|
if !vars[i].DeepEqual(someVars[i]) {
|
||||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: nginx-persistent-storage
|
- name: nginx-persistent-storage
|
||||||
mountPath: /tmp/ps
|
mountPath: /tmp/ps
|
||||||
|
- name: sidecar
|
||||||
|
image: sidecar:latest
|
||||||
volumes:
|
volumes:
|
||||||
- name: nginx-persistent-storage
|
- name: nginx-persistent-storage
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
@@ -138,8 +140,6 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: ANOTHERENV
|
- name: ANOTHERENV
|
||||||
value: FOO
|
value: FOO
|
||||||
- name: sidecar
|
|
||||||
image: sidecar
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: nginx-persistent-storage
|
- name: nginx-persistent-storage
|
||||||
`)
|
`)
|
||||||
@@ -187,7 +187,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /tmp/ps
|
- mountPath: /tmp/ps
|
||||||
name: nginx-persistent-storage
|
name: nginx-persistent-storage
|
||||||
- image: sidecar
|
- image: sidecar:latest
|
||||||
name: sidecar
|
name: sidecar
|
||||||
volumes:
|
volumes:
|
||||||
- gcePersistentDisk:
|
- gcePersistentDisk:
|
||||||
@@ -293,3 +293,258 @@ spec:
|
|||||||
t.Fatalf("Unexpected err: %v", err)
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMultiplePatchesWithPatchDeleteIgnored demonstrates that if the
|
||||||
|
// patch containing the $patch:delete directive is second in the list,
|
||||||
|
// the behavior of kustomize is incorrect, and the sidecar container is
|
||||||
|
// not removed from the final output. No conflict, nor error is reported
|
||||||
|
// even so the patch is ignored. See issue #1354
|
||||||
|
func TestMultiplePatchesWithPatchDeleteIgnored(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
|
||||||
|
makeCommonFileForMultiplePatchTest(th)
|
||||||
|
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", `
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
env:
|
||||||
|
- name: SOME_NAME
|
||||||
|
value: somevalue
|
||||||
|
`)
|
||||||
|
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", `
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- $patch: delete
|
||||||
|
name: sidecar
|
||||||
|
`)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-nginx
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- env:
|
||||||
|
- name: SOME_NAME
|
||||||
|
value: somevalue
|
||||||
|
image: nginx
|
||||||
|
name: nginx
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /tmp/ps
|
||||||
|
name: nginx-persistent-storage
|
||||||
|
- image: sidecar:latest
|
||||||
|
name: sidecar
|
||||||
|
volumes:
|
||||||
|
- emptyDir: {}
|
||||||
|
name: nginx-persistent-storage
|
||||||
|
- configMap:
|
||||||
|
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
||||||
|
name: configmap-in-base
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-nginx
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
selector:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
foo: bar
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
hello: world
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
env: staging
|
||||||
|
name: staging-configmap-in-overlay-k7cbc75tg8
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestMultiplePatchesWithPatchDeleteApplied demonstrates that if the
|
||||||
|
// patch containing the $patch:delete directive is first in the list,
|
||||||
|
// the behavior of kustomize is correct, and the sidecar container
|
||||||
|
// is removed from the final output. See issue #1354
|
||||||
|
func TestMultiplePatchesWithPatchDeleteApplied(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
|
||||||
|
makeCommonFileForMultiplePatchTest(th)
|
||||||
|
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", `
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- $patch: delete
|
||||||
|
name: sidecar
|
||||||
|
`)
|
||||||
|
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", `
|
||||||
|
apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
env:
|
||||||
|
- name: SOME_NAME
|
||||||
|
value: somevalue
|
||||||
|
`)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1beta2
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-nginx
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- env:
|
||||||
|
- name: SOME_NAME
|
||||||
|
value: somevalue
|
||||||
|
image: nginx
|
||||||
|
name: nginx
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /tmp/ps
|
||||||
|
name: nginx-persistent-storage
|
||||||
|
volumes:
|
||||||
|
- emptyDir: {}
|
||||||
|
name: nginx-persistent-storage
|
||||||
|
- configMap:
|
||||||
|
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
||||||
|
name: configmap-in-base
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-nginx
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
selector:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
foo: bar
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
note: This is a test annotation
|
||||||
|
labels:
|
||||||
|
app: mynginx
|
||||||
|
env: staging
|
||||||
|
org: example.com
|
||||||
|
team: foo
|
||||||
|
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
hello: world
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
env: staging
|
||||||
|
name: staging-configmap-in-overlay-k7cbc75tg8
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,3 +87,43 @@ metadata:
|
|||||||
type: Opaque
|
type: Opaque
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNamespacedGeneratorWithOverlays(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
|
||||||
|
th.WriteK("/app/base", `
|
||||||
|
namespace: base
|
||||||
|
|
||||||
|
configMapGenerator:
|
||||||
|
- name: testCase
|
||||||
|
literals:
|
||||||
|
- base=true
|
||||||
|
`)
|
||||||
|
th.WriteK("/app/overlay", `
|
||||||
|
resources:
|
||||||
|
- ../base
|
||||||
|
|
||||||
|
namespace: overlay
|
||||||
|
|
||||||
|
configMapGenerator:
|
||||||
|
- name: testCase
|
||||||
|
behavior: merge
|
||||||
|
literals:
|
||||||
|
- overlay=true
|
||||||
|
`)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
base: "true"
|
||||||
|
overlay: "true"
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
annotations: {}
|
||||||
|
labels: {}
|
||||||
|
name: testCase-4g75kbk6gm
|
||||||
|
namespace: overlay
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,19 +51,551 @@ resources:
|
|||||||
- role.yaml
|
- role.yaml
|
||||||
`)
|
`)
|
||||||
|
|
||||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
// TODO: Fix #1044
|
// This validates Fix #1444. This should not be an error anymore -
|
||||||
// This should not be an error -
|
|
||||||
// the secrets have the same name but are in different namespaces.
|
// the secrets have the same name but are in different namespaces.
|
||||||
// The ClusterRole (by def) is not in a namespace,
|
// The ClusterRole (by def) is not in a namespace,
|
||||||
// an in this case applies to *any* Secret resource
|
// an in this case applies to *any* Secret resource
|
||||||
// named "dummy"
|
// named "dummy"
|
||||||
if err == nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected lack of error")
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
if !strings.Contains(
|
th.AssertActualEqualsExpected(m, `
|
||||||
err.Error(),
|
apiVersion: v1
|
||||||
"slice case - multiple matches for ~G_v1_Secret|default|dummy") {
|
data:
|
||||||
t.Fatalf("unexpected error: %s", err)
|
dummy: ""
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: dummy
|
||||||
|
namespace: default
|
||||||
|
type: Opaque
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
dummy: ""
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: dummy
|
||||||
|
namespace: kube-system
|
||||||
|
type: Opaque
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: dummy
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resourceNames:
|
||||||
|
- dummy
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNameAndNsTransformation validates that NamespaceTransformer,
|
||||||
|
// PrefixSuffixTransformer and namereference transformers are
|
||||||
|
// able to deal with simultaneous change of namespace and name.
|
||||||
|
func TestNameAndNsTransformation(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/nameandns")
|
||||||
|
|
||||||
|
th.WriteK("/nameandns", `
|
||||||
|
namePrefix: p1-
|
||||||
|
nameSuffix: -s1
|
||||||
|
namespace: newnamespace
|
||||||
|
resources:
|
||||||
|
- resources.yaml
|
||||||
|
`)
|
||||||
|
|
||||||
|
th.WriteF("/nameandns/resources.yaml", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm2
|
||||||
|
namespace: ns1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc1
|
||||||
|
namespace: ns1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc2
|
||||||
|
namespace: ns1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: sa1
|
||||||
|
namespace: ns1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: sa2
|
||||||
|
namespace: ns1
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: manager-rolebinding
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: sa1
|
||||||
|
namespace: ns1
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: sa2
|
||||||
|
namespace: ns1
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: sa3
|
||||||
|
namespace: random
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: default
|
||||||
|
namespace: irrelevant
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
webhooks:
|
||||||
|
- name: example1
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc1
|
||||||
|
namespace: ns1
|
||||||
|
- name: example2
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc2
|
||||||
|
namespace: ns1
|
||||||
|
- name: example3
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc3
|
||||||
|
namespace: random
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: crds.my.org
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: cr1
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: crb1
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: default
|
||||||
|
namespace: irrelevant
|
||||||
|
---
|
||||||
|
kind: PersistentVolume
|
||||||
|
metadata:
|
||||||
|
name: pv1
|
||||||
|
`)
|
||||||
|
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: p1-cm1-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: p1-cm2-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: p1-svc1-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: p1-svc2-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: p1-sa1-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: p1-sa2-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: p1-manager-rolebinding-s1
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: p1-sa1-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: p1-sa2-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: sa3
|
||||||
|
namespace: random
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: default
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
name: p1-example-s1
|
||||||
|
webhooks:
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: p1-svc1-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
name: example1
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: p1-svc2-s1
|
||||||
|
namespace: newnamespace
|
||||||
|
name: example2
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc3
|
||||||
|
namespace: random
|
||||||
|
name: example3
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: crds.my.org
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: p1-cr1-s1
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: p1-crb1-s1
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: default
|
||||||
|
namespace: newnamespace
|
||||||
|
---
|
||||||
|
kind: PersistentVolume
|
||||||
|
metadata:
|
||||||
|
name: p1-pv1-s1
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This serie of constants is used to prove the need of
|
||||||
|
// the namespace field in the objref field of the var declaration.
|
||||||
|
// The following tests demonstrate that it creates umbiguous variable
|
||||||
|
// declaration if two entities of the kind with the same name
|
||||||
|
// but in different namespaces are declared.
|
||||||
|
// This is tracking the following issue:
|
||||||
|
// https://github.com/kubernetes-sigs/kustomize/issues/1298
|
||||||
|
const namespaceNeedInVarMyApp string = `
|
||||||
|
resources:
|
||||||
|
- elasticsearch-dev-service.yaml
|
||||||
|
- elasticsearch-test-service.yaml
|
||||||
|
vars:
|
||||||
|
- name: elasticsearch-test-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-test-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
- name: elasticsearch-dev-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-dev-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
`
|
||||||
|
|
||||||
|
const namespaceNeedInVarDevResources string = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: elasticsearch
|
||||||
|
env:
|
||||||
|
- name: DISCOVERY_SERVICE
|
||||||
|
value: "$(elasticsearch-dev-service-name).monitoring.svc.cluster.local"
|
||||||
|
- name: DISCOVERY_PROTOCOL
|
||||||
|
value: "$(elasticsearch-dev-protocol)"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: transport
|
||||||
|
port: 9300
|
||||||
|
protocol: TCP
|
||||||
|
clusterIP: None
|
||||||
|
`
|
||||||
|
|
||||||
|
const namespaceNeedInVarTestResources string = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: elasticsearch
|
||||||
|
env:
|
||||||
|
- name: DISCOVERY_SERVICE
|
||||||
|
value: "$(elasticsearch-test-service-name).monitoring.svc.cluster.local"
|
||||||
|
- name: DISCOVERY_PROTOCOL
|
||||||
|
value: "$(elasticsearch-test-protocol)"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: transport
|
||||||
|
port: 9300
|
||||||
|
protocol: UDP
|
||||||
|
clusterIP: None
|
||||||
|
`
|
||||||
|
|
||||||
|
const namespaceNeedInVarExpectedOutput string = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- env:
|
||||||
|
- name: DISCOVERY_SERVICE
|
||||||
|
value: elasticsearch.monitoring.svc.cluster.local
|
||||||
|
- name: DISCOVERY_PROTOCOL
|
||||||
|
value: TCP
|
||||||
|
name: elasticsearch
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
ports:
|
||||||
|
- name: transport
|
||||||
|
port: 9300
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- env:
|
||||||
|
- name: DISCOVERY_SERVICE
|
||||||
|
value: elasticsearch.monitoring.svc.cluster.local
|
||||||
|
- name: DISCOVERY_PROTOCOL
|
||||||
|
value: UDP
|
||||||
|
name: elasticsearch
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
ports:
|
||||||
|
- name: transport
|
||||||
|
port: 9300
|
||||||
|
protocol: UDP
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestVariablesAmbiguous demonstrates how two variables pointing at two different resources
|
||||||
|
// using the same name in different namespaces are treated as ambiguous if the namespace is
|
||||||
|
// not specified
|
||||||
|
func TestVariablesAmbiguous(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
|
||||||
|
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyApp)
|
||||||
|
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||||
|
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||||
|
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "unable to disambiguate") {
|
||||||
|
t.Fatalf("unexpected error %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const namespaceNeedInVarDevFolder string = `
|
||||||
|
resources:
|
||||||
|
- elasticsearch-dev-service.yaml
|
||||||
|
vars:
|
||||||
|
- name: elasticsearch-dev-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-dev-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
`
|
||||||
|
|
||||||
|
const namespaceNeedInVarTestFolder string = `
|
||||||
|
resources:
|
||||||
|
- elasticsearch-test-service.yaml
|
||||||
|
vars:
|
||||||
|
- name: elasticsearch-test-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-test-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestVariablesAmbiguousWorkaround demonstrates a possible workaround
|
||||||
|
// to TestVariablesAmbiguous problem. It requires to separate the variables
|
||||||
|
// and resources into multiple kustomization context/folders instead of one.
|
||||||
|
func TestVariablesAmbiguousWorkaround(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/workaround")
|
||||||
|
th.WriteK("/namespaceNeedInVar/dev", namespaceNeedInVarDevFolder)
|
||||||
|
th.WriteF("/namespaceNeedInVar/dev/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||||
|
th.WriteK("/namespaceNeedInVar/test", namespaceNeedInVarTestFolder)
|
||||||
|
th.WriteF("/namespaceNeedInVar/test/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||||
|
th.WriteK("/namespaceNeedInVar/workaround", `
|
||||||
|
resources:
|
||||||
|
- ../dev
|
||||||
|
- ../test
|
||||||
|
`)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
const namespaceNeedInVarMyAppWithNamespace string = `
|
||||||
|
resources:
|
||||||
|
- elasticsearch-dev-service.yaml
|
||||||
|
- elasticsearch-test-service.yaml
|
||||||
|
vars:
|
||||||
|
- name: elasticsearch-test-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-test-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: test
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
- name: elasticsearch-dev-service-name
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: metadata.name
|
||||||
|
- name: elasticsearch-dev-protocol
|
||||||
|
objref:
|
||||||
|
kind: Service
|
||||||
|
name: elasticsearch
|
||||||
|
namespace: dev
|
||||||
|
apiVersion: v1
|
||||||
|
fieldref:
|
||||||
|
fieldpath: spec.ports[0].protocol
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestVariablesDisambiguatedWithNamespace demonstrates that adding the namespace
|
||||||
|
// to the variable declarations allows to disambiguate the variables.
|
||||||
|
func TestVariablesDisambiguatedWithNamespace(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
|
||||||
|
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyAppWithNamespace)
|
||||||
|
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
|
||||||
|
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer"
|
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/target"
|
"sigs.k8s.io/kustomize/v3/pkg/target"
|
||||||
@@ -22,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestPluginDir(t *testing.T) {
|
func TestPluginDir(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
@@ -62,7 +63,7 @@ metadata:
|
|||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
rf := resmap.NewFactory(resource.NewFactory(
|
rf := resmap.NewFactory(resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl()))
|
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||||
|
|
||||||
pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf)
|
pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf)
|
||||||
tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl)
|
tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package target_test
|
package target_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
@@ -15,6 +14,8 @@ func writeBase(th *kusttest_test.KustTestHarness) {
|
|||||||
resources:
|
resources:
|
||||||
- serviceaccount.yaml
|
- serviceaccount.yaml
|
||||||
- rolebinding.yaml
|
- rolebinding.yaml
|
||||||
|
- clusterrolebinding.yaml
|
||||||
|
- clusterrole.yaml
|
||||||
namePrefix: pfx-
|
namePrefix: pfx-
|
||||||
nameSuffix: -sfx
|
nameSuffix: -sfx
|
||||||
`)
|
`)
|
||||||
@@ -31,11 +32,34 @@ metadata:
|
|||||||
name: rolebinding
|
name: rolebinding
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: role
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: serviceaccount
|
name: serviceaccount
|
||||||
|
`)
|
||||||
|
th.WriteF("/app/base/clusterrolebinding.yaml", `
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: rolebinding
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: serviceaccount
|
||||||
|
`)
|
||||||
|
th.WriteF("/app/base/clusterrole.yaml", `
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "watch", "list"]
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,11 +107,37 @@ metadata:
|
|||||||
name: pfx-rolebinding-sfx
|
name: pfx-rolebinding-sfx
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: pfx-role-sfx
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: pfx-serviceaccount-sfx
|
name: pfx-serviceaccount-sfx
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pfx-rolebinding-sfx
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: pfx-role-sfx
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pfx-serviceaccount-sfx
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: pfx-role-sfx
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,11 +161,37 @@ metadata:
|
|||||||
name: a-pfx-rolebinding-sfx-suffixA
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: a-pfx-role-sfx-suffixA
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: a-pfx-serviceaccount-sfx-suffixA
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,11 +215,37 @@ metadata:
|
|||||||
name: b-pfx-rolebinding-sfx-suffixB
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: b-pfx-role-sfx-suffixB
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: b-pfx-serviceaccount-sfx-suffixB
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,12 +270,38 @@ metadata:
|
|||||||
name: a-pfx-rolebinding-sfx-suffixA
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: a-pfx-role-sfx-suffixA
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: a-pfx-serviceaccount-sfx-suffixA
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
---
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
@@ -185,11 +313,37 @@ metadata:
|
|||||||
name: b-pfx-rolebinding-sfx-suffixB
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: ClusterRole
|
||||||
name: role
|
name: b-pfx-role-sfx-suffixB
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: b-pfx-serviceaccount-sfx-suffixB
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,12 +369,100 @@ metadata:
|
|||||||
name: serviceaccount
|
name: serviceaccount
|
||||||
`)
|
`)
|
||||||
|
|
||||||
_, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err == nil {
|
if err != nil {
|
||||||
t.Fatalf("Expected resource conflict.")
|
|
||||||
}
|
|
||||||
if !strings.Contains(
|
|
||||||
err.Error(), "multiple matches for ~G_v1_ServiceAccount") {
|
|
||||||
t.Fatalf("Unexpected err: %v", err)
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: a-serviceaccount-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-role-sfx-suffixA
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-role-sfx-suffixB
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- watch
|
||||||
|
- list
|
||||||
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeDeployment(th *kusttest_test.KustTestHarness, path string) {
|
func writeDeployment(th *kusttest_test.KustTestHarness, path string) {
|
||||||
@@ -50,7 +50,7 @@ metadata:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOrderedTransformers(t *testing.T) {
|
func TestOrderedTransformers(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -96,7 +96,7 @@ spec:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPluginsNotEnabled(t *testing.T) {
|
func TestPluginsNotEnabled(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -119,7 +119,7 @@ transformers:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSedTransformer(t *testing.T) {
|
func TestSedTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
@@ -187,7 +187,7 @@ metadata:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTransformedTransformers(t *testing.T) {
|
func TestTransformedTransformers(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ nameReference:
|
|||||||
- path: spec/initContainers/envFrom/configMapRef/name
|
- path: spec/initContainers/envFrom/configMapRef/name
|
||||||
version: v1
|
version: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
|
- path: spec/volumes/projected/sources/configMap/name
|
||||||
|
version: v1
|
||||||
|
kind: Pod
|
||||||
- path: spec/template/spec/volumes/configMap/name
|
- path: spec/template/spec/volumes/configMap/name
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
||||||
@@ -74,6 +77,8 @@ nameReference:
|
|||||||
kind: ReplicaSet
|
kind: ReplicaSet
|
||||||
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
||||||
kind: ReplicaSet
|
kind: ReplicaSet
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/configMap/name
|
||||||
|
kind: ReplicaSet
|
||||||
- path: spec/template/spec/volumes/configMap/name
|
- path: spec/template/spec/volumes/configMap/name
|
||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
||||||
@@ -84,6 +89,8 @@ nameReference:
|
|||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/configMap/name
|
||||||
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/volumes/configMap/name
|
- path: spec/template/spec/volumes/configMap/name
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
|
||||||
@@ -106,6 +113,8 @@ nameReference:
|
|||||||
kind: Job
|
kind: Job
|
||||||
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
|
||||||
kind: Job
|
kind: Job
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/configMap/name
|
||||||
|
kind: Job
|
||||||
- path: spec/jobTemplate/spec/template/spec/volumes/configMap/name
|
- path: spec/jobTemplate/spec/template/spec/volumes/configMap/name
|
||||||
kind: CronJob
|
kind: CronJob
|
||||||
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/configMap/name
|
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/configMap/name
|
||||||
@@ -140,6 +149,9 @@ nameReference:
|
|||||||
- path: spec/imagePullSecrets/name
|
- path: spec/imagePullSecrets/name
|
||||||
version: v1
|
version: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
|
- path: spec/volumes/projected/sources/secret/name
|
||||||
|
version: v1
|
||||||
|
kind: Pod
|
||||||
- path: spec/template/spec/volumes/secret/secretName
|
- path: spec/template/spec/volumes/secret/secretName
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
||||||
@@ -166,6 +178,8 @@ nameReference:
|
|||||||
kind: ReplicaSet
|
kind: ReplicaSet
|
||||||
- path: spec/template/spec/imagePullSecrets/name
|
- path: spec/template/spec/imagePullSecrets/name
|
||||||
kind: ReplicaSet
|
kind: ReplicaSet
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/secret/name
|
||||||
|
kind: ReplicaSet
|
||||||
- path: spec/template/spec/volumes/secret/secretName
|
- path: spec/template/spec/volumes/secret/secretName
|
||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
||||||
@@ -178,6 +192,8 @@ nameReference:
|
|||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/imagePullSecrets/name
|
- path: spec/template/spec/imagePullSecrets/name
|
||||||
kind: DaemonSet
|
kind: DaemonSet
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/secret/name
|
||||||
|
kind: DaemonSet
|
||||||
- path: spec/template/spec/volumes/secret/secretName
|
- path: spec/template/spec/volumes/secret/secretName
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
|
||||||
@@ -204,6 +220,8 @@ nameReference:
|
|||||||
kind: Job
|
kind: Job
|
||||||
- path: spec/template/spec/imagePullSecrets/name
|
- path: spec/template/spec/imagePullSecrets/name
|
||||||
kind: Job
|
kind: Job
|
||||||
|
- path: spec/template/spec/volumes/projected/sources/secret/name
|
||||||
|
kind: Job
|
||||||
- path: spec/jobTemplate/spec/template/spec/volumes/secret/secretName
|
- path: spec/jobTemplate/spec/template/spec/volumes/secret/secretName
|
||||||
kind: CronJob
|
kind: CronJob
|
||||||
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/secret/name
|
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/secret/name
|
||||||
@@ -254,10 +272,10 @@ nameReference:
|
|||||||
- path: spec/service/name
|
- path: spec/service/name
|
||||||
kind: APIService
|
kind: APIService
|
||||||
group: apiregistration.k8s.io
|
group: apiregistration.k8s.io
|
||||||
- path: webhooks/clientConfig/service/name
|
- path: webhooks/clientConfig/service
|
||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
group: admissionregistration.k8s.io
|
group: admissionregistration.k8s.io
|
||||||
- path: webhooks/clientConfig/service/name
|
- path: webhooks/clientConfig/service
|
||||||
kind: MutatingWebhookConfiguration
|
kind: MutatingWebhookConfiguration
|
||||||
group: admissionregistration.k8s.io
|
group: admissionregistration.k8s.io
|
||||||
|
|
||||||
@@ -281,10 +299,10 @@ nameReference:
|
|||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
version: v1
|
version: v1
|
||||||
fieldSpecs:
|
fieldSpecs:
|
||||||
- path: subjects/name
|
- path: subjects
|
||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
group: rbac.authorization.k8s.io
|
group: rbac.authorization.k8s.io
|
||||||
- path: subjects/name
|
- path: subjects
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
group: rbac.authorization.k8s.io
|
group: rbac.authorization.k8s.io
|
||||||
- path: spec/serviceAccountName
|
- path: spec/serviceAccountName
|
||||||
@@ -325,6 +343,8 @@ nameReference:
|
|||||||
fieldSpecs:
|
fieldSpecs:
|
||||||
- path: spec/volumeName
|
- path: spec/volumeName
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
|
- path: rules/resourceNames
|
||||||
|
kind: ClusterRole
|
||||||
|
|
||||||
- kind: StorageClass
|
- kind: StorageClass
|
||||||
version: v1
|
version: v1
|
||||||
@@ -334,5 +354,7 @@ nameReference:
|
|||||||
kind: PersistentVolume
|
kind: PersistentVolume
|
||||||
- path: spec/storageClassName
|
- path: spec/storageClassName
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
|
- path: spec/volumeClaimTemplates/spec/storageClassName
|
||||||
|
kind: StatefulSet
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,5 +21,9 @@ const (
|
|||||||
namespace:
|
namespace:
|
||||||
- path: metadata/namespace
|
- path: metadata/namespace
|
||||||
create: true
|
create: true
|
||||||
|
- path: subjects
|
||||||
|
kind: RoleBinding
|
||||||
|
- path: subjects
|
||||||
|
kind: ClusterRoleBinding
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -106,6 +106,107 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// selectReferral picks the referral among a subset of candidates.
|
||||||
|
// It returns the current name and namespace of the selected candidate.
|
||||||
|
// Note that the content of the referricalCandidateSubset slice is most of the time
|
||||||
|
// identical to the referralCandidates resmap. Still in some cases, such
|
||||||
|
// as ClusterRoleBinding, the subset only contains the resources of a specific
|
||||||
|
// namespace.
|
||||||
|
func (o *nameReferenceTransformer) selectReferral(
|
||||||
|
oldName string,
|
||||||
|
referrer *resource.Resource,
|
||||||
|
target gvk.Gvk,
|
||||||
|
referralCandidates resmap.ResMap,
|
||||||
|
referralCandidateSubset []*resource.Resource) (interface{}, interface{}, error) {
|
||||||
|
|
||||||
|
for _, res := range referralCandidateSubset {
|
||||||
|
id := res.OrgId()
|
||||||
|
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||||
|
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
|
||||||
|
// If there's more than one match, there's no way
|
||||||
|
// to know which one to pick, so emit error.
|
||||||
|
if len(matches) > 1 {
|
||||||
|
return nil, nil, fmt.Errorf(
|
||||||
|
"multiple matches for %s:\n %v",
|
||||||
|
id, getIds(matches))
|
||||||
|
}
|
||||||
|
// In the resource, note that it is referenced
|
||||||
|
// by the referrer.
|
||||||
|
res.AppendRefBy(referrer.CurId())
|
||||||
|
// Return transformed name of the object,
|
||||||
|
// complete with prefixes, hashes, etc.
|
||||||
|
return res.GetName(), res.GetNamespace(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldName, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility function to replace a simple string by the new name
|
||||||
|
func (o *nameReferenceTransformer) getSimpleNameField(
|
||||||
|
oldName string,
|
||||||
|
referrer *resource.Resource,
|
||||||
|
target gvk.Gvk,
|
||||||
|
referralCandidates resmap.ResMap,
|
||||||
|
referralCandidateSubset []*resource.Resource) (interface{}, error) {
|
||||||
|
|
||||||
|
newName, _, err := o.selectReferral(oldName, referrer, target,
|
||||||
|
referralCandidates, referralCandidateSubset)
|
||||||
|
|
||||||
|
return newName, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility function to replace name field within a map[string]interface{}
|
||||||
|
// and leverage the namespace field.
|
||||||
|
func (o *nameReferenceTransformer) getNameAndNsStruct(
|
||||||
|
inMap map[string]interface{},
|
||||||
|
referrer *resource.Resource,
|
||||||
|
target gvk.Gvk,
|
||||||
|
referralCandidates resmap.ResMap) (interface{}, error) {
|
||||||
|
|
||||||
|
// Example:
|
||||||
|
if _, ok := inMap["name"]; !ok {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"%#v is expected to contain a name field", inMap)
|
||||||
|
}
|
||||||
|
oldName, ok := inMap["name"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"%#v is expected to contain a name field of type string", oldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
subset := referralCandidates.Resources()
|
||||||
|
if namespacevalue, ok := inMap["namespace"]; ok {
|
||||||
|
namespace := namespacevalue.(string)
|
||||||
|
bynamespace := referralCandidates.GroupedByOriginalNamespace()
|
||||||
|
if _, ok := bynamespace[namespace]; !ok {
|
||||||
|
return inMap, nil
|
||||||
|
}
|
||||||
|
subset = bynamespace[namespace]
|
||||||
|
}
|
||||||
|
|
||||||
|
newname, newnamespace, err := o.selectReferral(oldName, referrer, target,
|
||||||
|
referralCandidates, subset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newname == oldName) && (newnamespace == nil) {
|
||||||
|
// no candidate found.
|
||||||
|
return inMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
inMap["name"] = newname
|
||||||
|
if newnamespace != "" {
|
||||||
|
// We don't want value "" to replace value "default" since
|
||||||
|
// the empty string is handled as a wild card here not default namespace
|
||||||
|
// by kubernetes.
|
||||||
|
inMap["namespace"] = newnamespace
|
||||||
|
}
|
||||||
|
return inMap, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (o *nameReferenceTransformer) getNewNameFunc(
|
func (o *nameReferenceTransformer) getNewNameFunc(
|
||||||
referrer *resource.Resource,
|
referrer *resource.Resource,
|
||||||
target gvk.Gvk,
|
target gvk.Gvk,
|
||||||
@@ -114,52 +215,46 @@ func (o *nameReferenceTransformer) getNewNameFunc(
|
|||||||
switch in.(type) {
|
switch in.(type) {
|
||||||
case string:
|
case string:
|
||||||
oldName, _ := in.(string)
|
oldName, _ := in.(string)
|
||||||
for _, res := range referralCandidates.Resources() {
|
return o.getSimpleNameField(oldName, referrer, target,
|
||||||
id := res.OrgId()
|
referralCandidates, referralCandidates.Resources())
|
||||||
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
case map[string]interface{}:
|
||||||
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
// Kind: ValidatingWebhookConfiguration
|
||||||
// If there's more than one match, there's no way
|
// FieldSpec is webhooks/clientConfig/service
|
||||||
// to know which one to pick, so emit error.
|
oldMap, _ := in.(map[string]interface{})
|
||||||
if len(matches) > 1 {
|
return o.getNameAndNsStruct(oldMap, referrer, target,
|
||||||
return nil, fmt.Errorf(
|
referralCandidates)
|
||||||
"string case - multiple matches for %s:\n %v",
|
|
||||||
id, getIds(matches))
|
|
||||||
}
|
|
||||||
// In the resource, note that it is referenced
|
|
||||||
// by the referrer.
|
|
||||||
res.AppendRefBy(referrer.CurId())
|
|
||||||
// Return transformed name of the object,
|
|
||||||
// complete with prefixes, hashes, etc.
|
|
||||||
return res.GetName(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in, nil
|
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
l, _ := in.([]interface{})
|
l, _ := in.([]interface{})
|
||||||
var names []string
|
for idx, item := range l {
|
||||||
for _, item := range l {
|
switch item.(type) {
|
||||||
name, ok := item.(string)
|
case string:
|
||||||
if !ok {
|
// Kind: Role/ClusterRole
|
||||||
|
// FieldSpec is rules.resourceNames
|
||||||
|
oldName, _ := item.(string)
|
||||||
|
newName, err := o.getSimpleNameField(oldName, referrer, target,
|
||||||
|
referralCandidates, referralCandidates.Resources())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l[idx] = newName
|
||||||
|
case map[string]interface{}:
|
||||||
|
// Kind: RoleBinding/ClusterRoleBinding
|
||||||
|
// FieldSpec is subjects
|
||||||
|
// Note: The corresponding fieldSpec had been changed from
|
||||||
|
// from path: subjects/name to just path: subjects. This is
|
||||||
|
// what get mutatefield to request the mapping of the whole
|
||||||
|
// map containing namespace and name instead of just a simple
|
||||||
|
// string field containing the name
|
||||||
|
oldMap, _ := item.(map[string]interface{})
|
||||||
|
newMap, err := o.getNameAndNsStruct(oldMap, referrer, target,
|
||||||
|
referralCandidates)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l[idx] = newMap
|
||||||
|
default:
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"%#v is expected to be %T", item, name)
|
"%#v is expected to be either a []string or a []map[string]interface{}", in)
|
||||||
}
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
|
||||||
for _, res := range referralCandidates.Resources() {
|
|
||||||
indexes := indexOf(res.GetOriginalName(), names)
|
|
||||||
id := res.OrgId()
|
|
||||||
if id.IsSelected(&target) && len(indexes) > 0 {
|
|
||||||
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
|
||||||
if len(matches) > 1 {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"slice case - multiple matches for %s:\n %v",
|
|
||||||
id, getIds(matches))
|
|
||||||
}
|
|
||||||
for _, index := range indexes {
|
|
||||||
l[index] = res.GetName()
|
|
||||||
}
|
|
||||||
res.AppendRefBy(referrer.CurId())
|
|
||||||
return l, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return in, nil
|
return in, nil
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
@@ -466,6 +468,7 @@ func TestNameReferenceHappyRun(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
@@ -497,7 +500,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).ResMap(),
|
}).ResMap(),
|
||||||
expectedErr: "is expected to be string"},
|
expectedErr: "is expected to be"},
|
||||||
{
|
{
|
||||||
resMap: resmaptest_test.NewRmBuilder(t, rf).Add(
|
resMap: resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
@@ -517,7 +520,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).ResMap(),
|
}).ResMap(),
|
||||||
expectedErr: "is expected to be either a string or a []interface{}"},
|
expectedErr: "is expected to contain a name field"},
|
||||||
}
|
}
|
||||||
|
|
||||||
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
@@ -590,3 +593,469 @@ func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
|||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utility map to create a deployment object
|
||||||
|
// with (metadatanamespace, metadataname) as key
|
||||||
|
// and pointing to "refname" secret and configmap
|
||||||
|
func deploymentMap(metadatanamespace string, metadataname string,
|
||||||
|
configmapref string, secretref string) map[string]interface{} {
|
||||||
|
deployment := map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": metadataname,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
"env": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "CM_FOO",
|
||||||
|
"valueFrom": map[string]interface{}{
|
||||||
|
"configMapKeyRef": map[string]interface{}{
|
||||||
|
"name": configmapref,
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "SECRET_FOO",
|
||||||
|
"valueFrom": map[string]interface{}{
|
||||||
|
"secretKeyRef": map[string]interface{}{
|
||||||
|
"name": secretref,
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadatanamespace != "" {
|
||||||
|
metadata := deployment["metadata"].(map[string]interface{})
|
||||||
|
metadata["namespace"] = metadatanamespace
|
||||||
|
}
|
||||||
|
return deployment
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultNs = "default"
|
||||||
|
ns1 = "ns1"
|
||||||
|
ns2 = "ns2"
|
||||||
|
ns3 = "ns3"
|
||||||
|
ns4 = "ns4"
|
||||||
|
|
||||||
|
orgname = "uniquename"
|
||||||
|
prefixedname = "prefix-uniquename"
|
||||||
|
suffixedname = "uniquename-suffix"
|
||||||
|
modifiedname = "modifiedname"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestNameReferenceNamespace creates serviceAccount and clusterRoleBinding
|
||||||
|
// object with the same original names (uniquename) in different namespaces
|
||||||
|
// and with different current Id.
|
||||||
|
func TestNameReferenceNamespace(t *testing.T) {
|
||||||
|
rf := resource.NewFactory(
|
||||||
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
// Add ConfigMap with the same org name in noNs, "ns1" and "ns2" namespaces
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns1, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns2, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
}}).
|
||||||
|
// Add Secret with the same org name in noNs, "ns1" and "ns2" namespaces
|
||||||
|
AddWithNsAndName(defaultNs, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
"namespace": defaultNs,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns1, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns2, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
}}).
|
||||||
|
// Add Deployment with the same org name in noNs, "ns1" and "ns2" namespaces
|
||||||
|
AddWithNsAndName(defaultNs, orgname, deploymentMap(defaultNs, modifiedname, modifiedname, modifiedname)).
|
||||||
|
AddWithNsAndName(ns1, orgname, deploymentMap(ns1, prefixedname, orgname, orgname)).
|
||||||
|
AddWithNsAndName(ns2, orgname, deploymentMap(ns2, suffixedname, orgname, orgname)).ResMap()
|
||||||
|
|
||||||
|
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
|
||||||
|
ReplaceResource(deploymentMap(defaultNs, modifiedname, modifiedname, modifiedname)).
|
||||||
|
ReplaceResource(deploymentMap(ns1, prefixedname, prefixedname, prefixedname)).
|
||||||
|
ReplaceResource(deploymentMap(ns2, suffixedname, suffixedname, suffixedname)).ResMap()
|
||||||
|
|
||||||
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
|
err := nrt.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNameReferenceNamespace creates serviceAccount and clusterRoleBinding
|
||||||
|
// object with the same original names (uniquename) in different namespaces
|
||||||
|
// and with different current Id.
|
||||||
|
func TestNameReferenceClusterWide(t *testing.T) {
|
||||||
|
rf := resource.NewFactory(
|
||||||
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
// Add ServiceAccount with the same org name in noNs, "ns1" and "ns2" namespaces
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns1, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName(ns2, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
}}).
|
||||||
|
// Add a PersistentVolume to have a clusterwide resource
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "PersistentVolume",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
}}).
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
"rules": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"resources": []interface{}{
|
||||||
|
"persistentvolumes",
|
||||||
|
},
|
||||||
|
"resourceNames": []interface{}{
|
||||||
|
orgname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}).
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
"roleRef": map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"name": orgname,
|
||||||
|
},
|
||||||
|
"subjects": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": defaultNs,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns1,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns2,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": "random",
|
||||||
|
},
|
||||||
|
}}).ResMap()
|
||||||
|
|
||||||
|
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
|
||||||
|
ReplaceResource(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
// Behavior of the transformer is still imperfect
|
||||||
|
// It should use the (resources,apigroup,resourceNames) as
|
||||||
|
// combination to select the candidates.
|
||||||
|
"rules": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"resources": []interface{}{
|
||||||
|
"persistentvolumes",
|
||||||
|
},
|
||||||
|
"resourceNames": []interface{}{
|
||||||
|
modifiedname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}).
|
||||||
|
ReplaceResource(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
"roleRef": map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
// The following tests required a change in
|
||||||
|
// getNameFunc implementation in order to leverage
|
||||||
|
// the namespace field.
|
||||||
|
"subjects": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": modifiedname,
|
||||||
|
"namespace": defaultNs,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": "random",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).ResMap()
|
||||||
|
|
||||||
|
clusterRoleId := resid.NewResId(
|
||||||
|
gvk.Gvk{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}, modifiedname)
|
||||||
|
clusterRoleBindingId := resid.NewResId(
|
||||||
|
gvk.Gvk{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}, modifiedname)
|
||||||
|
clusterRole, _ := expected.GetByCurrentId(clusterRoleId)
|
||||||
|
clusterRole.AppendRefBy(clusterRoleBindingId)
|
||||||
|
|
||||||
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
|
err := nrt.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNameReferenceNamespaceTransformation creates serviceAccount and clusterRoleBinding
|
||||||
|
// object with the same original names (uniquename) in different namespaces
|
||||||
|
// and with different current Id.
|
||||||
|
func TestNameReferenceNamespaceTransformation(t *testing.T) {
|
||||||
|
rf := resource.NewFactory(
|
||||||
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
AddWithNsAndName(ns4, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns4,
|
||||||
|
}}).
|
||||||
|
// Add ServiceAccount with the same org name in "ns1" namespaces
|
||||||
|
AddWithNsAndName(ns1, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
}}).
|
||||||
|
// Simulate NamespaceTransformer effect (ns3 transformed in ns2)
|
||||||
|
AddWithNsAndName(ns3, orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
}}).
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
}}).
|
||||||
|
AddWithName(orgname, map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
"roleRef": map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"name": orgname,
|
||||||
|
},
|
||||||
|
"subjects": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns1,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns3,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": "random",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns4,
|
||||||
|
},
|
||||||
|
}}).ResMap()
|
||||||
|
|
||||||
|
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
|
||||||
|
ReplaceResource(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
"roleRef": map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRole",
|
||||||
|
"name": modifiedname,
|
||||||
|
},
|
||||||
|
// The following tests required a change in
|
||||||
|
// getNameFunc implementation in order to leverage
|
||||||
|
// the namespace field.
|
||||||
|
"subjects": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": prefixedname,
|
||||||
|
"namespace": ns1,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": suffixedname,
|
||||||
|
"namespace": ns2,
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": "random",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
|
"name": orgname,
|
||||||
|
"namespace": ns4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).ResMap()
|
||||||
|
|
||||||
|
clusterRoleId := resid.NewResId(
|
||||||
|
gvk.Gvk{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}, modifiedname)
|
||||||
|
clusterRoleBindingId := resid.NewResId(
|
||||||
|
gvk.Gvk{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}, modifiedname)
|
||||||
|
clusterRole, _ := expected.GetByCurrentId(clusterRoleId)
|
||||||
|
clusterRole.AppendRefBy(clusterRoleBindingId)
|
||||||
|
|
||||||
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
|
err := nrt.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNameReferenceNamespace creates configmap, secret, deployment
|
||||||
|
// It validates the change done is IsSameFuzzyNamespace which
|
||||||
|
// uses the IsNsEquals method instead of the simple == operator.
|
||||||
|
func TestNameReferenceCandidateSelection(t *testing.T) {
|
||||||
|
rf := resource.NewFactory(
|
||||||
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
AddWithName("cm1", map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "p1-cm1-hash",
|
||||||
|
}}).
|
||||||
|
AddWithNsAndName("default", "secret1", map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "p1-secret1-hash",
|
||||||
|
"namespace": "default",
|
||||||
|
}}).
|
||||||
|
AddWithName("deploy1", deploymentMap("", "p1-deploy1", "cm1", "secret1")).
|
||||||
|
ResMap()
|
||||||
|
|
||||||
|
expected := resmaptest_test.NewSeededRmBuilder(t, rf, m.ShallowCopy()).
|
||||||
|
ReplaceResource(deploymentMap("", "p1-deploy1", "p1-cm1-hash", "p1-secret1-hash")).
|
||||||
|
ResMap()
|
||||||
|
|
||||||
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
|
err := nrt.Transform(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
55
pkg/types/fix.go
Normal file
55
pkg/types/fix.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package types holds struct definitions that should find a better home.
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FixKustomizationPreUnmarshalling modies the raw data
|
||||||
|
// before marshalling - e.g. changes old field names to
|
||||||
|
// new field names.
|
||||||
|
func FixKustomizationPreUnmarshalling(data []byte) []byte {
|
||||||
|
deprecateFieldsMap := map[string]string{
|
||||||
|
"imageTags:": "images:",
|
||||||
|
}
|
||||||
|
for oldname, newname := range deprecateFieldsMap {
|
||||||
|
pattern := regexp.MustCompile(oldname)
|
||||||
|
data = pattern.ReplaceAll(data, []byte(newname))
|
||||||
|
}
|
||||||
|
|
||||||
|
if useLegacyPatch(data) {
|
||||||
|
pattern := regexp.MustCompile("patches:")
|
||||||
|
data = pattern.ReplaceAll(data, []byte("patchesStrategicMerge:"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func useLegacyPatch(data []byte) bool {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
var object map[string]interface{}
|
||||||
|
err := yaml.Unmarshal(data, &object)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("invalid content from %s\n", string(data))
|
||||||
|
}
|
||||||
|
if rawPatches, ok := object["patches"]; ok {
|
||||||
|
patches, ok := rawPatches.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("invalid patches from %v\n", rawPatches)
|
||||||
|
}
|
||||||
|
for _, p := range patches {
|
||||||
|
_, ok := p.(string)
|
||||||
|
if ok {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
@@ -5,8 +5,6 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/image"
|
"sigs.k8s.io/kustomize/v3/pkg/image"
|
||||||
)
|
)
|
||||||
@@ -195,21 +193,6 @@ func (k *Kustomization) EnforceFields() []string {
|
|||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// FixKustomizationPreUnmarshalling modies the raw data
|
|
||||||
// before marshalling - e.g. changes old field names to
|
|
||||||
// new field names.
|
|
||||||
func FixKustomizationPreUnmarshalling(data []byte) []byte {
|
|
||||||
deprecateFieldsMap := map[string]string{
|
|
||||||
"patches:": "patchesStrategicMerge:",
|
|
||||||
"imageTags:": "images:",
|
|
||||||
}
|
|
||||||
for oldname, newname := range deprecateFieldsMap {
|
|
||||||
pattern := regexp.MustCompile(oldname)
|
|
||||||
data = pattern.ReplaceAll(data, []byte(newname))
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// GeneratorArgs contains arguments common to generators.
|
// GeneratorArgs contains arguments common to generators.
|
||||||
type GeneratorArgs struct {
|
type GeneratorArgs struct {
|
||||||
// Namespace for the configmap, optional
|
// Namespace for the configmap, optional
|
||||||
@@ -386,7 +369,7 @@ type Patch struct {
|
|||||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
|
|
||||||
// Target points to the resources that the patch is applied to
|
// Target points to the resources that the patch is applied to
|
||||||
Target Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selector specifies a set of resources.
|
// Selector specifies a set of resources.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ type Target struct {
|
|||||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||||
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldSelector contains the fieldPath to an object field.
|
// FieldSelector contains the fieldPath to an object field.
|
||||||
@@ -64,10 +66,22 @@ type FieldSelector struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// defaulting sets reference to field used by default.
|
// defaulting sets reference to field used by default.
|
||||||
func (v *Var) defaulting() {
|
func (v *Var) Defaulting() {
|
||||||
if v.FieldRef.FieldPath == "" {
|
if v.FieldRef.FieldPath == "" {
|
||||||
v.FieldRef.FieldPath = defaultFieldPath
|
v.FieldRef.FieldPath = defaultFieldPath
|
||||||
}
|
}
|
||||||
|
v.ObjRef.GVK()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepEqual returns true if var a and b are Equals.
|
||||||
|
// Note 1: The objects are unchanged by the VarEqual
|
||||||
|
// Note 2: Should be normalize be FieldPath before doing
|
||||||
|
// the DeepEqual. spec.a[b] is supposed to be the same
|
||||||
|
// as spec.a.b
|
||||||
|
func (v Var) DeepEqual(other Var) bool {
|
||||||
|
v.Defaulting()
|
||||||
|
other.Defaulting()
|
||||||
|
return reflect.DeepEqual(v, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarSet is a set of Vars where no var.Name is repeated.
|
// VarSet is a set of Vars where no var.Name is repeated.
|
||||||
@@ -129,11 +143,52 @@ func (vs *VarSet) Merge(v Var) error {
|
|||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"var '%s' already encountered", v.Name)
|
"var '%s' already encountered", v.Name)
|
||||||
}
|
}
|
||||||
v.defaulting()
|
v.Defaulting()
|
||||||
vs.set[v.Name] = v
|
vs.set[v.Name] = v
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AbsorbSet absorbs other vars with error on (name,value) collision.
|
||||||
|
func (vs *VarSet) AbsorbSet(incoming VarSet) error {
|
||||||
|
for _, v := range incoming.set {
|
||||||
|
if err := vs.Absorb(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbsorbSlice absorbs a Var slice with error on (name,value) collision.
|
||||||
|
// Empty fields in incoming vars are defaulted.
|
||||||
|
func (vs *VarSet) AbsorbSlice(incoming []Var) error {
|
||||||
|
for _, v := range incoming {
|
||||||
|
if err := vs.Absorb(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absorb absorbs another Var with error on (name,value) collision.
|
||||||
|
// Empty fields in incoming Var is defaulted.
|
||||||
|
func (vs *VarSet) Absorb(v Var) error {
|
||||||
|
conflicting := vs.Get(v.Name)
|
||||||
|
if conflicting == nil {
|
||||||
|
// no conflict. The var is valid.
|
||||||
|
v.Defaulting()
|
||||||
|
vs.set[v.Name] = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(v, *conflicting) {
|
||||||
|
// two vars with the same name are pointing at two
|
||||||
|
// different resources.
|
||||||
|
return fmt.Errorf(
|
||||||
|
"var '%s' already encountered", v.Name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Contains is true if the set has the other var.
|
// Contains is true if the set has the other var.
|
||||||
func (vs *VarSet) Contains(other Var) bool {
|
func (vs *VarSet) Contains(other Var) bool {
|
||||||
return vs.Get(other.Name) != nil
|
return vs.Get(other.Name) != nil
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func TestDefaulting(t *testing.T) {
|
|||||||
Name: "my-secret",
|
Name: "my-secret",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
v.defaulting()
|
v.Defaulting()
|
||||||
if v.FieldRef.FieldPath != defaultFieldPath {
|
if v.FieldRef.FieldPath != defaultFieldPath {
|
||||||
t.Fatalf("expected %s, got %v",
|
t.Fatalf("expected %s, got %v",
|
||||||
defaultFieldPath, v.FieldRef.FieldPath)
|
defaultFieldPath, v.FieldRef.FieldPath)
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ func (p *ImageTagTransformerPlugin) findContainers(obj map[string]interface{}) e
|
|||||||
|
|
||||||
func isImageMatched(s, t string) bool {
|
func isImageMatched(s, t string) bool {
|
||||||
// Tag values are limited to [a-zA-Z0-9_.-].
|
// Tag values are limited to [a-zA-Z0-9_.-].
|
||||||
pattern, _ := regexp.Compile("^" + t + "(:[a-zA-Z0-9_.-]*)?$")
|
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
|
||||||
return pattern.MatchString(s)
|
return pattern.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ func split(imageName string) (name string, tag string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i := ic
|
i := ic
|
||||||
if ic < 0 {
|
if ia > 0 {
|
||||||
i = ia
|
i = ia
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
package builtin
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
@@ -36,22 +35,23 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
id := r.OrgId()
|
|
||||||
fs, ok := p.isSelected(id)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(r.Map()) == 0 {
|
if len(r.Map()) == 0 {
|
||||||
// Don't mutate empty objects?
|
// Don't mutate empty objects?
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if doIt(id, fs) {
|
|
||||||
if err := p.changeNamespace(r, fs); err != nil {
|
id := r.OrgId()
|
||||||
|
applicableFs := p.applicableFieldSpecs(id)
|
||||||
|
|
||||||
|
for _, fs := range applicableFs {
|
||||||
|
err := transformers.MutateField(
|
||||||
|
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
||||||
|
p.changeNamespace(r))
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.updateClusterRoleBinding(m)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,67 +61,64 @@ const metaNamespace = "metadata/namespace"
|
|||||||
// all objects have it, even "ClusterKind" objects
|
// all objects have it, even "ClusterKind" objects
|
||||||
// that don't exist in a namespace (the Namespace
|
// that don't exist in a namespace (the Namespace
|
||||||
// object itself doesn't live in a namespace).
|
// object itself doesn't live in a namespace).
|
||||||
func doIt(id resid.ResId, fs *config.FieldSpec) bool {
|
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []config.FieldSpec {
|
||||||
return fs.Path != metaNamespace ||
|
res := []config.FieldSpec{}
|
||||||
(fs.Path == metaNamespace && id.IsNamespaceableKind())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *NamespaceTransformerPlugin) changeNamespace(
|
|
||||||
r *resource.Resource, fs *config.FieldSpec) error {
|
|
||||||
return transformers.MutateField(
|
|
||||||
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
|
||||||
func(_ interface{}) (interface{}, error) {
|
|
||||||
return p.Namespace, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *NamespaceTransformerPlugin) isSelected(
|
|
||||||
id resid.ResId) (*config.FieldSpec, bool) {
|
|
||||||
for _, fs := range p.FieldSpecs {
|
for _, fs := range p.FieldSpecs {
|
||||||
if id.IsSelected(&fs.Gvk) {
|
if id.IsSelected(&fs.Gvk) && (fs.Path != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
|
||||||
return &fs, true
|
res = append(res, fs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NamespaceTransformerPlugin) updateClusterRoleBinding(m resmap.ResMap) {
|
func (o *NamespaceTransformerPlugin) changeNamespace(
|
||||||
srvAccount := gvk.Gvk{Version: "v1", Kind: "ServiceAccount"}
|
referrer *resource.Resource) func(in interface{}) (interface{}, error) {
|
||||||
saMap := map[string]bool{}
|
return func(in interface{}) (interface{}, error) {
|
||||||
for _, id := range m.AllIds() {
|
switch in.(type) {
|
||||||
if id.Gvk.Equals(srvAccount) {
|
case string:
|
||||||
saMap[id.Name] = true
|
// will happen when the metadata/namespace
|
||||||
}
|
// value is replaced
|
||||||
}
|
return o.Namespace, nil
|
||||||
|
case []interface{}:
|
||||||
for _, res := range m.Resources() {
|
l, _ := in.([]interface{})
|
||||||
if res.OrgId().Kind != "ClusterRoleBinding" &&
|
for idx, item := range l {
|
||||||
res.OrgId().Kind != "RoleBinding" {
|
switch item.(type) {
|
||||||
continue
|
case map[string]interface{}:
|
||||||
}
|
// Will happen when mutating the subjects
|
||||||
objMap := res.Map()
|
// field of ClusterRoleBinding and RoleBinding
|
||||||
subjects, ok := objMap["subjects"].([]interface{})
|
inMap, _ := item.(map[string]interface{})
|
||||||
if subjects == nil || !ok {
|
if _, ok := inMap["name"]; !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := range subjects {
|
name, ok := inMap["name"].(string)
|
||||||
subject := subjects[i].(map[string]interface{})
|
if !ok {
|
||||||
kind, foundK := subject["kind"]
|
continue
|
||||||
name, foundN := subject["name"]
|
}
|
||||||
if !foundK || !foundN || kind.(string) != srvAccount.Kind {
|
// The only case we need to force the namespace
|
||||||
continue
|
// if for the "service account". "default" is
|
||||||
|
// kind of hardcoded here for right now.
|
||||||
|
if name != "default" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inMap["namespace"] = o.Namespace
|
||||||
|
l[idx] = inMap
|
||||||
|
default:
|
||||||
|
// nothing to do for right now
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// a ServiceAccount named “default” exists in every active namespace
|
return in, nil
|
||||||
if name.(string) == "default" || saMap[name.(string)] {
|
case map[string]interface{}:
|
||||||
subject := subjects[i].(map[string]interface{})
|
// Will happen if the createField=true
|
||||||
transformers.MutateField(
|
// when the namespace is added to the
|
||||||
subject, []string{"namespace"},
|
// object
|
||||||
true, func(_ interface{}) (interface{}, error) {
|
inMap := in.(map[string]interface{})
|
||||||
return p.Namespace, nil
|
if len(inMap) == 0 {
|
||||||
})
|
return o.Namespace, nil
|
||||||
subjects[i] = subject
|
} else {
|
||||||
|
return in, nil
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return in, nil
|
||||||
}
|
}
|
||||||
objMap["subjects"] = subjects
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
plugin/builtin/PatchStrategicMergeTransformer.go
Normal file
83
plugin/builtin/PatchStrategicMergeTransformer.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
|
||||||
|
package builtin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PatchStrategicMergeTransformerPlugin struct {
|
||||||
|
ldr ifc.Loader
|
||||||
|
rf *resmap.Factory
|
||||||
|
loadedPatches []*resource.Resource
|
||||||
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
|
Patches string `json:patches,omitempty" yaml:"patches,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
func NewPatchStrategicMergeTransformerPlugin() *PatchStrategicMergeTransformerPlugin {
|
||||||
|
return &PatchStrategicMergeTransformerPlugin{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
||||||
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
|
p.ldr = ldr
|
||||||
|
p.rf = rf
|
||||||
|
err = yaml.Unmarshal(c, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(p.Paths) == 0 && p.Patches == "" {
|
||||||
|
return fmt.Errorf("empty file path and empty patch content")
|
||||||
|
}
|
||||||
|
if len(p.Paths) != 0 {
|
||||||
|
res, err := p.rf.RF().SliceFromPatches(ldr, p.Paths)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = res
|
||||||
|
}
|
||||||
|
if p.Patches != "" {
|
||||||
|
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.loadedPatches) == 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
|
patches, err := p.rf.MergePatches(p.loadedPatches)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, patch := range patches.Resources() {
|
||||||
|
target, err := m.GetById(patch.OrgId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = target.Patch(patch.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// remove the resource from resmap
|
||||||
|
// when the patch is to $patch: delete that target
|
||||||
|
if len(target.Map()) == 0 {
|
||||||
|
err = m.Remove(target.CurId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
148
plugin/builtin/PatchTransformer.go
Normal file
148
plugin/builtin/PatchTransformer.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
|
||||||
|
package builtin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/evanphx/json-patch"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PatchTransformerPlugin struct {
|
||||||
|
ldr ifc.Loader
|
||||||
|
rf *resmap.Factory
|
||||||
|
loadedPatch *resource.Resource
|
||||||
|
decodedPatch jsonpatch.Patch
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
|
Target *types.Selector `json:"target,omitempty", yaml:"target,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
func NewPatchTransformerPlugin() *PatchTransformerPlugin {
|
||||||
|
return &PatchTransformerPlugin{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PatchTransformerPlugin) Config(
|
||||||
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
|
p.ldr = ldr
|
||||||
|
p.rf = rf
|
||||||
|
err = yaml.Unmarshal(c, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p.Patch == "" && p.Path == "" {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"must specify one of patch and path in\n%s", string(c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.Patch != "" && p.Path != "" {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"patch and path can't be set at the same time\n%s", string(c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var in []byte
|
||||||
|
if p.Path != "" {
|
||||||
|
in, err = ldr.Load(p.Path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.Patch != "" {
|
||||||
|
in = []byte(p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
patchSM, errSM := p.rf.RF().FromBytes(in)
|
||||||
|
patchJson, errJson := jsonPatchFromBytes(in)
|
||||||
|
if errSM != nil && errJson != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if errSM == nil && errJson != nil {
|
||||||
|
p.loadedPatch = patchSM
|
||||||
|
}
|
||||||
|
if errJson == nil && errSM != nil {
|
||||||
|
p.decodedPatch = patchJson
|
||||||
|
}
|
||||||
|
if patchSM != nil && patchJson != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
|
if p.loadedPatch != nil && p.Target == nil {
|
||||||
|
target, err := m.GetById(p.loadedPatch.OrgId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = target.Patch(p.loadedPatch.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Target == nil {
|
||||||
|
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
resources, err := m.Select(*p.Target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, resource := range resources {
|
||||||
|
if p.decodedPatch != nil {
|
||||||
|
rawObj, err := resource.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(
|
||||||
|
err, "failed to apply json patch '%s'", p.Patch)
|
||||||
|
}
|
||||||
|
err = resource.UnmarshalJSON(modifiedObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.loadedPatch != nil {
|
||||||
|
patchCopy := p.loadedPatch.DeepCopy()
|
||||||
|
patchCopy.SetName(resource.GetName())
|
||||||
|
patchCopy.SetNamespace(resource.GetNamespace())
|
||||||
|
patchCopy.SetGvk(resource.GetGvk())
|
||||||
|
err = resource.Patch(patchCopy.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonPatchFromBytes loads a Json 6902 patch from
|
||||||
|
// a bytes input
|
||||||
|
func jsonPatchFromBytes(
|
||||||
|
in []byte) (jsonpatch.Patch, error) {
|
||||||
|
ops := string(in)
|
||||||
|
if ops == "" {
|
||||||
|
return nil, fmt.Errorf("empty json patch operations")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ops[0] != '[' {
|
||||||
|
jsonOps, err := yaml.YAMLToJSON(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ops = string(jsonOps)
|
||||||
|
}
|
||||||
|
return jsonpatch.DecodePatch([]byte(ops))
|
||||||
|
}
|
||||||
@@ -49,22 +49,40 @@ func (p *PrefixSuffixTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
|
||||||
return nil
|
// Even if both the Prefix and Suffix are empty we want
|
||||||
}
|
// to proceed with the transformation. This allows to add contextual
|
||||||
|
// information to the resources (AddNamePrefix and AddNameSuffix).
|
||||||
|
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if p.shouldSkip(r.OrgId()) {
|
if p.shouldSkip(r.OrgId()) {
|
||||||
|
// Don't change the actual definition
|
||||||
|
// of a CRD.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
id := r.OrgId()
|
id := r.OrgId()
|
||||||
|
// current default configuration contains
|
||||||
|
// only one entry: "metadata/name" with no GVK
|
||||||
for _, path := range p.FieldSpecs {
|
for _, path := range p.FieldSpecs {
|
||||||
if !id.IsSelected(&path.Gvk) {
|
if !id.IsSelected(&path.Gvk) {
|
||||||
|
// With the currrent default configuration,
|
||||||
|
// because no Gvk is specified, so a wild
|
||||||
|
// card
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if smellsLikeANameChange(&path) {
|
if smellsLikeANameChange(&path) {
|
||||||
|
// "metadata/name" is the only field.
|
||||||
|
// this will add a prefix and a suffix
|
||||||
|
// to the resource even if those are
|
||||||
|
// empty
|
||||||
r.AddNamePrefix(p.Prefix)
|
r.AddNamePrefix(p.Prefix)
|
||||||
r.AddNameSuffix(p.Suffix)
|
r.AddNameSuffix(p.Suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the addPrefixSuffix method will not
|
||||||
|
// change the name if both the prefix and suffix
|
||||||
|
// are empty.
|
||||||
err := transformers.MutateField(
|
err := transformers.MutateField(
|
||||||
r.Map(),
|
r.Map(),
|
||||||
path.PathSlice(),
|
path.PathSlice(),
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAnnotationsTransformer(t *testing.T) {
|
func TestAnnotationsTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigMapGenerator(t *testing.T) {
|
func TestConfigMapGenerator(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHashTransformer(t *testing.T) {
|
func TestHashTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ func (p *plugin) findContainers(obj map[string]interface{}) error {
|
|||||||
|
|
||||||
func isImageMatched(s, t string) bool {
|
func isImageMatched(s, t string) bool {
|
||||||
// Tag values are limited to [a-zA-Z0-9_.-].
|
// Tag values are limited to [a-zA-Z0-9_.-].
|
||||||
pattern, _ := regexp.Compile("^" + t + "(:[a-zA-Z0-9_.-]*)?$")
|
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
|
||||||
return pattern.MatchString(s)
|
return pattern.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ func split(imageName string) (name string, tag string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i := ic
|
i := ic
|
||||||
if ic < 0 {
|
if ia > 0 {
|
||||||
i = ia
|
i = ia
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestImageTagTransformer(t *testing.T) {
|
func TestImageTagTransformerNewTag(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -36,18 +36,22 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
initContainers:
|
|
||||||
- name: nginx2
|
|
||||||
image: my-nginx:1.8.0
|
|
||||||
- name: init-alpine
|
|
||||||
image: alpine:1.8.0
|
|
||||||
containers:
|
containers:
|
||||||
- name: ngnix
|
- image: nginx:1.7.9
|
||||||
image: nginx:1.7.9
|
name: nginx-tagged
|
||||||
- name: repliaced-with-digest
|
- image: nginx:latest
|
||||||
image: foobar:1
|
name: nginx-latest
|
||||||
- name: postgresdb
|
- image: foobar:1
|
||||||
image: postgres:1.8.0
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
`)
|
`)
|
||||||
|
|
||||||
th.AssertActualEqualsExpected(rm, `
|
th.AssertActualEqualsExpected(rm, `
|
||||||
@@ -61,14 +65,307 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: nginx:v2
|
- image: nginx:v2
|
||||||
name: ngnix
|
name: nginx-tagged
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-latest
|
||||||
- image: foobar:1
|
- image: foobar:1
|
||||||
name: repliaced-with-digest
|
name: replaced-with-digest
|
||||||
- image: postgres:1.8.0
|
- image: postgres:1.8.0
|
||||||
name: postgresdb
|
name: postgresdb
|
||||||
initContainers:
|
initContainers:
|
||||||
- image: my-nginx:1.8.0
|
- image: nginx:v2
|
||||||
name: nginx2
|
name: nginx-notag
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
func TestImageTagTransformerNewImage(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "ImageTagTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ImageTagTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
imageTag:
|
||||||
|
name: nginx
|
||||||
|
newName: busybox
|
||||||
|
`, `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageTagTransformerNewImageAndTag(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "ImageTagTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ImageTagTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
imageTag:
|
||||||
|
name: nginx
|
||||||
|
newName: busybox
|
||||||
|
newTag: v2
|
||||||
|
`, `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox:v2
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox:v2
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox:v2
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox:v2
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageTagTransformerNewDigest(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "ImageTagTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ImageTagTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
imageTag:
|
||||||
|
name: nginx
|
||||||
|
Digest: sha256:222222222222222222
|
||||||
|
`, `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageTagTransformerNewImageAndDigest(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "ImageTagTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: ImageTagTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
imageTag:
|
||||||
|
name: nginx
|
||||||
|
newName: busybox
|
||||||
|
Digest: sha256:222222222222222222
|
||||||
|
`, `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-sha256
|
||||||
- image: alpine:1.8.0
|
- image: alpine:1.8.0
|
||||||
name: init-alpine
|
name: init-alpine
|
||||||
`)
|
`)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ package main_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -59,7 +59,7 @@ metadata:
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestInventoryTransformerCollect(t *testing.T) {
|
func TestInventoryTransformerCollect(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -80,7 +80,7 @@ policy: GarbageCollect
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInventoryTransformerIgnore(t *testing.T) {
|
func TestInventoryTransformerIgnore(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -101,7 +101,7 @@ policy: GarbageIgnore
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInventoryTransformerDefaultPolicy(t *testing.T) {
|
func TestInventoryTransformerDefaultPolicy(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLabelTransformer(t *testing.T) {
|
func TestLabelTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLegacyOrderTransformer(t *testing.T) {
|
func TestLegacyOrderTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
@@ -37,22 +36,23 @@ func (p *plugin) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
id := r.OrgId()
|
|
||||||
fs, ok := p.isSelected(id)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(r.Map()) == 0 {
|
if len(r.Map()) == 0 {
|
||||||
// Don't mutate empty objects?
|
// Don't mutate empty objects?
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if doIt(id, fs) {
|
|
||||||
if err := p.changeNamespace(r, fs); err != nil {
|
id := r.OrgId()
|
||||||
|
applicableFs := p.applicableFieldSpecs(id)
|
||||||
|
|
||||||
|
for _, fs := range applicableFs {
|
||||||
|
err := transformers.MutateField(
|
||||||
|
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
||||||
|
p.changeNamespace(r))
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.updateClusterRoleBinding(m)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,67 +62,64 @@ const metaNamespace = "metadata/namespace"
|
|||||||
// all objects have it, even "ClusterKind" objects
|
// all objects have it, even "ClusterKind" objects
|
||||||
// that don't exist in a namespace (the Namespace
|
// that don't exist in a namespace (the Namespace
|
||||||
// object itself doesn't live in a namespace).
|
// object itself doesn't live in a namespace).
|
||||||
func doIt(id resid.ResId, fs *config.FieldSpec) bool {
|
func (p *plugin) applicableFieldSpecs(id resid.ResId) []config.FieldSpec {
|
||||||
return fs.Path != metaNamespace ||
|
res := []config.FieldSpec{}
|
||||||
(fs.Path == metaNamespace && id.IsNamespaceableKind())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *plugin) changeNamespace(
|
|
||||||
r *resource.Resource, fs *config.FieldSpec) error {
|
|
||||||
return transformers.MutateField(
|
|
||||||
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
|
||||||
func(_ interface{}) (interface{}, error) {
|
|
||||||
return p.Namespace, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *plugin) isSelected(
|
|
||||||
id resid.ResId) (*config.FieldSpec, bool) {
|
|
||||||
for _, fs := range p.FieldSpecs {
|
for _, fs := range p.FieldSpecs {
|
||||||
if id.IsSelected(&fs.Gvk) {
|
if id.IsSelected(&fs.Gvk) && (fs.Path != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
|
||||||
return &fs, true
|
res = append(res, fs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) updateClusterRoleBinding(m resmap.ResMap) {
|
func (o *plugin) changeNamespace(
|
||||||
srvAccount := gvk.Gvk{Version: "v1", Kind: "ServiceAccount"}
|
referrer *resource.Resource) func(in interface{}) (interface{}, error) {
|
||||||
saMap := map[string]bool{}
|
return func(in interface{}) (interface{}, error) {
|
||||||
for _, id := range m.AllIds() {
|
switch in.(type) {
|
||||||
if id.Gvk.Equals(srvAccount) {
|
case string:
|
||||||
saMap[id.Name] = true
|
// will happen when the metadata/namespace
|
||||||
}
|
// value is replaced
|
||||||
}
|
return o.Namespace, nil
|
||||||
|
case []interface{}:
|
||||||
for _, res := range m.Resources() {
|
l, _ := in.([]interface{})
|
||||||
if res.OrgId().Kind != "ClusterRoleBinding" &&
|
for idx, item := range l {
|
||||||
res.OrgId().Kind != "RoleBinding" {
|
switch item.(type) {
|
||||||
continue
|
case map[string]interface{}:
|
||||||
}
|
// Will happen when mutating the subjects
|
||||||
objMap := res.Map()
|
// field of ClusterRoleBinding and RoleBinding
|
||||||
subjects, ok := objMap["subjects"].([]interface{})
|
inMap, _ := item.(map[string]interface{})
|
||||||
if subjects == nil || !ok {
|
if _, ok := inMap["name"]; !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := range subjects {
|
name, ok := inMap["name"].(string)
|
||||||
subject := subjects[i].(map[string]interface{})
|
if !ok {
|
||||||
kind, foundK := subject["kind"]
|
continue
|
||||||
name, foundN := subject["name"]
|
}
|
||||||
if !foundK || !foundN || kind.(string) != srvAccount.Kind {
|
// The only case we need to force the namespace
|
||||||
continue
|
// if for the "service account". "default" is
|
||||||
|
// kind of hardcoded here for right now.
|
||||||
|
if name != "default" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inMap["namespace"] = o.Namespace
|
||||||
|
l[idx] = inMap
|
||||||
|
default:
|
||||||
|
// nothing to do for right now
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// a ServiceAccount named “default” exists in every active namespace
|
return in, nil
|
||||||
if name.(string) == "default" || saMap[name.(string)] {
|
case map[string]interface{}:
|
||||||
subject := subjects[i].(map[string]interface{})
|
// Will happen if the createField=true
|
||||||
transformers.MutateField(
|
// when the namespace is added to the
|
||||||
subject, []string{"namespace"},
|
// object
|
||||||
true, func(_ interface{}) (interface{}, error) {
|
inMap := in.(map[string]interface{})
|
||||||
return p.Namespace, nil
|
if len(inMap) == 0 {
|
||||||
})
|
return o.Namespace, nil
|
||||||
subjects[i] = subject
|
} else {
|
||||||
|
return in, nil
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return in, nil
|
||||||
}
|
}
|
||||||
objMap["subjects"] = subjects
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNamespaceTransformer1(t *testing.T) {
|
func TestNamespaceTransformer1(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -28,6 +28,12 @@ metadata:
|
|||||||
fieldSpecs:
|
fieldSpecs:
|
||||||
- path: metadata/namespace
|
- path: metadata/namespace
|
||||||
create: true
|
create: true
|
||||||
|
- path: subjects
|
||||||
|
kind: RoleBinding
|
||||||
|
group: rbac.authorization.k8s.io
|
||||||
|
- path: subjects
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
group: rbac.authorization.k8s.io
|
||||||
`, `
|
`, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
@@ -41,6 +47,11 @@ metadata:
|
|||||||
namespace: foo
|
namespace: foo
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: ns1
|
name: ns1
|
||||||
@@ -49,7 +60,7 @@ apiVersion: v1
|
|||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: default
|
name: default
|
||||||
namespace: system
|
namespace: test
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
@@ -72,12 +83,37 @@ subjects:
|
|||||||
name: another
|
name: another
|
||||||
namespace: random
|
namespace: random
|
||||||
---
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
webhooks:
|
||||||
|
- name: example1
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc1
|
||||||
|
namespace: system
|
||||||
|
- name: example2
|
||||||
|
clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc2
|
||||||
|
namespace: system
|
||||||
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
name: crd
|
name: crd
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
// Import note: The namespace transformer is in charge of
|
||||||
|
// the metadata.namespace field. The namespace transformer SHOULD
|
||||||
|
// NOT modify neither the "namespace" subfield within the
|
||||||
|
// ClusterRoleBinding.subjects field nor the "namespace"
|
||||||
|
// subfield in the ValidatingWebhookConfiguration.webhooks field.
|
||||||
|
// This is the role of the namereference Transformer to handle
|
||||||
|
// object reference changes (prefix/suffix and namespace).
|
||||||
|
// For use cases involving simultaneous change of name and namespace,
|
||||||
|
// refer to namespaces tests in pkg/target test suites.
|
||||||
th.AssertActualEqualsExpected(rm, `
|
th.AssertActualEqualsExpected(rm, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
@@ -92,6 +128,12 @@ metadata:
|
|||||||
namespace: test
|
namespace: test
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc1
|
||||||
|
namespace: test
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: ns1
|
name: ns1
|
||||||
@@ -118,11 +160,27 @@ subjects:
|
|||||||
namespace: test
|
namespace: test
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: service-account
|
name: service-account
|
||||||
namespace: test
|
namespace: system
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: another
|
name: another
|
||||||
namespace: random
|
namespace: random
|
||||||
---
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
webhooks:
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc1
|
||||||
|
namespace: system
|
||||||
|
name: example1
|
||||||
|
- clientConfig:
|
||||||
|
service:
|
||||||
|
name: svc2
|
||||||
|
namespace: system
|
||||||
|
name: example2
|
||||||
|
---
|
||||||
apiVersion: apiextensions.k8s.io/v1beta1
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
@@ -131,7 +189,7 @@ metadata:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceTransformerClusterLevelKinds(t *testing.T) {
|
func TestNamespaceTransformerClusterLevelKinds(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -170,6 +228,12 @@ metadata:
|
|||||||
fieldSpecs:
|
fieldSpecs:
|
||||||
- path: metadata/namespace
|
- path: metadata/namespace
|
||||||
create: true
|
create: true
|
||||||
|
- path: subjects
|
||||||
|
kind: RoleBinding
|
||||||
|
group: rbac.authorization.k8s.io
|
||||||
|
- path: subjects
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
group: rbac.authorization.k8s.io
|
||||||
`, noChangeExpected)
|
`, noChangeExpected)
|
||||||
|
|
||||||
th.AssertActualEqualsExpected(rm, noChangeExpected)
|
th.AssertActualEqualsExpected(rm, noChangeExpected)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
const target = `
|
const target = `
|
||||||
@@ -29,7 +29,7 @@ spec:
|
|||||||
`
|
`
|
||||||
|
|
||||||
func TestPatchJson6902TransformerMissingFile(t *testing.T) {
|
func TestPatchJson6902TransformerMissingFile(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -58,7 +58,7 @@ path: jsonpatch.json
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBadPatchJson6902Transformer(t *testing.T) {
|
func TestBadPatchJson6902Transformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -87,7 +87,7 @@ jsonOp: 'thisIsNotAPatch'
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBothEmptyJson6902Transformer(t *testing.T) {
|
func TestBothEmptyJson6902Transformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -115,7 +115,7 @@ target:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBothSpecifiedJson6902Transformer(t *testing.T) {
|
func TestBothSpecifiedJson6902Transformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -151,7 +151,7 @@ jsonOp: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "Clust
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchJson6902TransformerFromJsonFile(t *testing.T) {
|
func TestPatchJson6902TransformerFromJsonFile(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -201,7 +201,7 @@ spec:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchJson6902TransformerFromYamlFile(t *testing.T) {
|
func TestPatchJson6902TransformerFromYamlFile(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
@@ -251,7 +251,7 @@ spec:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPatchJson6902TransformerWithInline(t *testing.T) {
|
func TestPatchJson6902TransformerWithInline(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
//go:generate go run sigs.k8s.io/kustomize/v3/cmd/pluginator
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type plugin struct {
|
||||||
|
ldr ifc.Loader
|
||||||
|
rf *resmap.Factory
|
||||||
|
loadedPatches []*resource.Resource
|
||||||
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
|
Patches string `json:patches,omitempty" yaml:"patches,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
|
func (p *plugin) Config(
|
||||||
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
|
p.ldr = ldr
|
||||||
|
p.rf = rf
|
||||||
|
err = yaml.Unmarshal(c, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(p.Paths) == 0 && p.Patches == "" {
|
||||||
|
return fmt.Errorf("empty file path and empty patch content")
|
||||||
|
}
|
||||||
|
if len(p.Paths) != 0 {
|
||||||
|
res, err := p.rf.RF().SliceFromPatches(ldr, p.Paths)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = res
|
||||||
|
}
|
||||||
|
if p.Patches != "" {
|
||||||
|
res, err := p.rf.RF().SliceFromBytes([]byte(p.Patches))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = append(p.loadedPatches, res...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.loadedPatches) == 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
|
patches, err := p.rf.MergePatches(p.loadedPatches)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, patch := range patches.Resources() {
|
||||||
|
target, err := m.GetById(patch.OrgId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = target.Patch(patch.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// remove the resource from resmap
|
||||||
|
// when the patch is to $patch: delete that target
|
||||||
|
if len(target.Map()) == 0 {
|
||||||
|
err = m.Remove(target.CurId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
149
plugin/builtin/patchtransformer/PatchTransformer.go
Normal file
149
plugin/builtin/patchtransformer/PatchTransformer.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
//go:generate go run sigs.k8s.io/kustomize/v3/cmd/pluginator
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/evanphx/json-patch"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type plugin struct {
|
||||||
|
ldr ifc.Loader
|
||||||
|
rf *resmap.Factory
|
||||||
|
loadedPatch *resource.Resource
|
||||||
|
decodedPatch jsonpatch.Patch
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
|
Target *types.Selector `json:"target,omitempty", yaml:"target,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
|
func (p *plugin) Config(
|
||||||
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
|
p.ldr = ldr
|
||||||
|
p.rf = rf
|
||||||
|
err = yaml.Unmarshal(c, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p.Patch == "" && p.Path == "" {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"must specify one of patch and path in\n%s", string(c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.Patch != "" && p.Path != "" {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"patch and path can't be set at the same time\n%s", string(c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var in []byte
|
||||||
|
if p.Path != "" {
|
||||||
|
in, err = ldr.Load(p.Path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.Patch != "" {
|
||||||
|
in = []byte(p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
patchSM, errSM := p.rf.RF().FromBytes(in)
|
||||||
|
patchJson, errJson := jsonPatchFromBytes(in)
|
||||||
|
if errSM != nil && errJson != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if errSM == nil && errJson != nil {
|
||||||
|
p.loadedPatch = patchSM
|
||||||
|
}
|
||||||
|
if errJson == nil && errSM != nil {
|
||||||
|
p.decodedPatch = patchJson
|
||||||
|
}
|
||||||
|
if patchSM != nil && patchJson != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
|
if p.loadedPatch != nil && p.Target == nil {
|
||||||
|
target, err := m.GetById(p.loadedPatch.OrgId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = target.Patch(p.loadedPatch.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Target == nil {
|
||||||
|
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
resources, err := m.Select(*p.Target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, resource := range resources {
|
||||||
|
if p.decodedPatch != nil {
|
||||||
|
rawObj, err := resource.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(
|
||||||
|
err, "failed to apply json patch '%s'", p.Patch)
|
||||||
|
}
|
||||||
|
err = resource.UnmarshalJSON(modifiedObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.loadedPatch != nil {
|
||||||
|
patchCopy := p.loadedPatch.DeepCopy()
|
||||||
|
patchCopy.SetName(resource.GetName())
|
||||||
|
patchCopy.SetNamespace(resource.GetNamespace())
|
||||||
|
patchCopy.SetGvk(resource.GetGvk())
|
||||||
|
err = resource.Patch(patchCopy.Kunstructured)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonPatchFromBytes loads a Json 6902 patch from
|
||||||
|
// a bytes input
|
||||||
|
func jsonPatchFromBytes(
|
||||||
|
in []byte) (jsonpatch.Patch, error) {
|
||||||
|
ops := string(in)
|
||||||
|
if ops == "" {
|
||||||
|
return nil, fmt.Errorf("empty json patch operations")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ops[0] != '[' {
|
||||||
|
jsonOps, err := yaml.YAMLToJSON(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ops = string(jsonOps)
|
||||||
|
}
|
||||||
|
return jsonpatch.DecodePatch([]byte(ops))
|
||||||
|
}
|
||||||
341
plugin/builtin/patchtransformer/PatchTransformer_test.go
Normal file
341
plugin/builtin/patchtransformer/PatchTransformer_test.go
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package main_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
target = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: yourDeploy
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
replica: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:1.7.9
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
label:
|
||||||
|
old-label: old-value
|
||||||
|
kind: MyKind
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPatchTransformerMissingFile(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
path: patch.yaml
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(),
|
||||||
|
"cannot read file \"/app/patch.yaml\"") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerBadPatch(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
patch: "thisIsNotAPatch"
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(),
|
||||||
|
"unable to get either a Strategic Merge Patch or JSON patch 6902 from") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerMissingSelector(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
patch: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]'
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(),
|
||||||
|
"must specify a target for patch") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerBothEmptyPathAndPatch(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "must specify one of patch and path in") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerBothNonEmptyPathAndPatch(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
Path: patch.yaml
|
||||||
|
Patch: "something"
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "patch and path can't be set at the same time") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerFromFiles(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
th.WriteF("/app/patch.yaml", `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
`)
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
path: patch.yaml
|
||||||
|
target:
|
||||||
|
name: .*Deploy
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
name: yourDeploy
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: MyKind
|
||||||
|
metadata:
|
||||||
|
label:
|
||||||
|
old-label: old-value
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchTransformerWithInline(t *testing.T) {
|
||||||
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchTransformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
patch: '[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "nginx:latest"}]'
|
||||||
|
target:
|
||||||
|
name: .*Deploy
|
||||||
|
kind: Deployment
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
name: yourDeploy
|
||||||
|
spec:
|
||||||
|
replica: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
new-label: new-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: MyKind
|
||||||
|
metadata:
|
||||||
|
label:
|
||||||
|
old-label: old-value
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
`)
|
||||||
|
}
|
||||||
@@ -50,22 +50,40 @@ func (p *plugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
|
||||||
return nil
|
// Even if both the Prefix and Suffix are empty we want
|
||||||
}
|
// to proceed with the transformation. This allows to add contextual
|
||||||
|
// information to the resources (AddNamePrefix and AddNameSuffix).
|
||||||
|
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if p.shouldSkip(r.OrgId()) {
|
if p.shouldSkip(r.OrgId()) {
|
||||||
|
// Don't change the actual definition
|
||||||
|
// of a CRD.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
id := r.OrgId()
|
id := r.OrgId()
|
||||||
|
// current default configuration contains
|
||||||
|
// only one entry: "metadata/name" with no GVK
|
||||||
for _, path := range p.FieldSpecs {
|
for _, path := range p.FieldSpecs {
|
||||||
if !id.IsSelected(&path.Gvk) {
|
if !id.IsSelected(&path.Gvk) {
|
||||||
|
// With the currrent default configuration,
|
||||||
|
// because no Gvk is specified, so a wild
|
||||||
|
// card
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if smellsLikeANameChange(&path) {
|
if smellsLikeANameChange(&path) {
|
||||||
|
// "metadata/name" is the only field.
|
||||||
|
// this will add a prefix and a suffix
|
||||||
|
// to the resource even if those are
|
||||||
|
// empty
|
||||||
r.AddNamePrefix(p.Prefix)
|
r.AddNamePrefix(p.Prefix)
|
||||||
r.AddNameSuffix(p.Suffix)
|
r.AddNameSuffix(p.Suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the addPrefixSuffix method will not
|
||||||
|
// change the name if both the prefix and suffix
|
||||||
|
// are empty.
|
||||||
err := transformers.MutateField(
|
err := transformers.MutateField(
|
||||||
r.Map(),
|
r.Map(),
|
||||||
path.PathSlice(),
|
path.PathSlice(),
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPrefixSuffixTransformer(t *testing.T) {
|
func TestPrefixSuffixTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReplicaCountTransformer(t *testing.T) {
|
func TestReplicaCountTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSecretGenerator(t *testing.T) {
|
func TestSecretGenerator(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBashedConfigMapPlugin(t *testing.T) {
|
func TestBashedConfigMapPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This test requires having the helm binary on the PATH.
|
// This test requires having the helm binary on the PATH.
|
||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
// TODO: Download and inflate the chart, and check that
|
// TODO: Download and inflate the chart, and check that
|
||||||
// in for the test.
|
// in for the test.
|
||||||
func TestChartInflator(t *testing.T) {
|
func TestChartInflator(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDatePrefixerPlugin(t *testing.T) {
|
func TestDatePrefixerPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func shouldContain(t *testing.T, s []byte, x string) {
|
func shouldContain(t *testing.T, s []byte, x string) {
|
||||||
@@ -18,7 +18,7 @@ func shouldContain(t *testing.T, s []byte, x string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrintWorkDirPlugin(t *testing.T) {
|
func TestPrintWorkDirPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin(
|
tc.BuildExecPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSecretsFromDatabasePlugin(t *testing.T) {
|
func TestSecretsFromDatabasePlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSedTransformer(t *testing.T) {
|
func TestSedTransformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin("someteam.example.com", "v1", "SedTransformer")
|
tc.BuildExecPlugin("someteam.example.com", "v1", "SedTransformer")
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSomeServiceGeneratorPlugin(t *testing.T) {
|
func TestSomeServiceGeneratorPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStringPrefixerPlugin(t *testing.T) {
|
func TestStringPrefixerPlugin(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildGoPlugin(
|
tc.BuildGoPlugin(
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidatorHappy(t *testing.T) {
|
func TestValidatorHappy(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")
|
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")
|
||||||
@@ -49,7 +49,7 @@ metadata:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidatorUnHappy(t *testing.T) {
|
func TestValidatorUnHappy(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins_test.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")
|
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ git tag -a $version -m "Release $version"
|
|||||||
```
|
```
|
||||||
|
|
||||||
### trigger the cloud build
|
### trigger the cloud build
|
||||||
|
Push the tag:
|
||||||
Pushing the tag will trigger a job in [Google Cloud
|
|
||||||
Build] to put a new release on the [releases page].
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git push upstream $version
|
git push upstream $version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This triggers a job in [Google Cloud Build] to
|
||||||
|
put a new release on the [release page].
|
||||||
|
|
||||||
### Update release notes
|
### Update release notes
|
||||||
|
|
||||||
Visit the [release page] and edit the release notes as desired.
|
Visit the [release page] and edit the release notes as desired.
|
||||||
|
|||||||
Reference in New Issue
Block a user