Compare commits

..

1 Commits

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

View File

@@ -1,7 +1,5 @@
# 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
files for multiple purposes, leaving the original YAML
untouched and usable as is.
@@ -24,7 +22,7 @@ these [instructions](docs/INSTALL.md).
Browse the [docs](docs) or jump right into the
tested [examples](examples).
kustomize [v2.0.3] is available in [kubectl v1.14 and v1.15][kubectl].
kustomize [v2.0.3] is available in [kubectl v1.15][kubectl].
## Usage

View File

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

View File

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

View File

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

View File

@@ -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
[changes]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md
[adapt]: https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/types/kustomization.go#L166
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#resources
[special]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#resources
[k8s API]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
[conventions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
[release process]: ../releasing/README.md
[kustomization]: glossary.md#kustomization
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds
[`kind`]: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#types-kinds
[`apiVersion`]: https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning
[semantic versioning]: https://semver.org

14
go.mod
View File

@@ -6,16 +6,10 @@ require (
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
github.com/evanphx/json-patch v4.5.0+incompatible
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/google/gofuzz v1.0.0 // indirect
github.com/googleapis/gnostic v0.3.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/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/spf13/cobra v0.0.2
github.com/spf13/pflag v1.0.3
@@ -23,10 +17,10 @@ require (
golang.org/x/sys v0.0.0-20190621203818-d432491b9138 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20190313235455-40a48860b5ab
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1
k8s.io/client-go v11.0.0+incompatible
k8s.io/api v0.0.0-20190809220925-3ab596449d6f
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010
k8s.io/client-go v0.0.0-20190812221009-4f902818859a
k8s.io/klog v0.3.3 // indirect
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058
sigs.k8s.io/yaml v1.1.0
)

48
go.sum
View File

@@ -1,3 +1,5 @@
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/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
@@ -10,9 +12,13 @@ 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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
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 v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
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/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@@ -32,26 +38,40 @@ 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/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.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
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/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 v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-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/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/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/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/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
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.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.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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -63,13 +83,16 @@ 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-20190620125010-da37f6c1e481 h1:IaSjLMT6WvkoZZjspGxy3rdaTEmWLoRm49WbtVUi9sA=
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/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/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
@@ -77,11 +100,13 @@ 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 v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/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/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -92,21 +117,27 @@ 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 v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
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/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-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-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-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-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
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-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/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/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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -118,17 +149,22 @@ 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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
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=
@@ -139,17 +175,27 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
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/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/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/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog 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/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/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058 h1:di3XCwddOR9cWBNpfgXaskhh6cgJuwcK54rvtwUaC10=
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/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -20,10 +20,6 @@ package kunstruct
import (
"encoding/json"
"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"
"sigs.k8s.io/kustomize/v3/pkg/types"
@@ -69,11 +65,6 @@ 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.
func (fs *UnstructAdapter) Copy() ifc.Kunstructured {
return &UnstructAdapter{*fs.DeepCopy()}
@@ -294,59 +285,3 @@ func (fs *UnstructAdapter) MatchesAnnotationSelector(selector string) (bool, err
}
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)
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,
}
}

View File

@@ -6,8 +6,8 @@ package transformer
import (
"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/transformers"
)
// FactoryImpl makes patch transformer and name hash transformer
@@ -18,8 +18,9 @@ func NewFactoryImpl() *FactoryImpl {
return &FactoryImpl{}
}
func (p *FactoryImpl) MergePatches(patches []*resource.Resource,
rf *resource.Factory) (
resmap.ResMap, error) {
return patch.MergePatches(patches, rf)
// MakePatchTransformer makes a new patch transformer
func (p *FactoryImpl) MakePatchTransformer(
slice []*resource.Resource,
rf *resource.Factory) (transformers.Transformer, error) {
return patch.NewTransformer(slice, rf)
}

View File

@@ -5,11 +5,6 @@ package patch
import (
"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"
"k8s.io/apimachinery/pkg/runtime"
@@ -127,64 +122,3 @@ func (smp *strategicMergePatch) mergePatches(patch1, patch2 *resource.Resource)
smp.lookupPatchMeta, patch1.Map(), patch2.Map())
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.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(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,
}
}

View File

@@ -0,0 +1,156 @@
// 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,
}
}

View File

@@ -0,0 +1,579 @@
// 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)
}
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/v3/pkg/fs"
"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/pgmconfig"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
@@ -60,7 +61,7 @@ https://github.com/hashicorp/go-getter#url-format
func NewCmdBuild(
out io.Writer, fSys fs.FileSystem,
v ifc.Validator, rf *resmap.Factory,
ptf resmap.PatchFactory) *cobra.Command {
ptf transformer.Factory) *cobra.Command {
var o Options
pluginConfig := plugins.DefaultPluginConfig()
@@ -114,7 +115,7 @@ func (o *Options) Validate(args []string) (err error) {
// RunBuild runs build command.
func (o *Options) RunBuild(
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
rf *resmap.Factory, ptf resmap.PatchFactory,
rf *resmap.Factory, ptf transformer.Factory,
pl *plugins.Loader) error {
ldr, err := loader.NewLoader(
o.loadRestrictor, v, o.kustomizationPath, fSys)
@@ -135,7 +136,7 @@ func (o *Options) RunBuild(
func (o *Options) RunBuildPrune(
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
rf *resmap.Factory, ptf resmap.PatchFactory,
rf *resmap.Factory, ptf transformer.Factory,
pl *plugins.Loader) error {
ldr, err := loader.NewLoader(
o.loadRestrictor, v, o.kustomizationPath, fSys)
@@ -179,7 +180,7 @@ func (o *Options) emitResources(
func NewCmdBuildPrune(
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
rf *resmap.Factory, ptf resmap.PatchFactory,
rf *resmap.Factory, ptf transformer.Factory,
pl *plugins.Loader) *cobra.Command {
var o Options
@@ -201,7 +202,7 @@ func NewCmdBuildPrune(
func writeIndividualFiles(
fSys fs.FileSystem, folderPath string, m resmap.ResMap) error {
byNamespace := m.GroupedByCurrentNamespace()
byNamespace := m.GroupedByNamespace()
for namespace, resList := range byNamespace {
for _, res := range resList {
fName := fileName(res)

View File

@@ -36,13 +36,12 @@ See https://sigs.k8s.io/kustomize
}
uf := kunstruct.NewKunstructuredFactoryImpl()
pf := transformer.NewFactoryImpl()
rf := resmap.NewFactory(resource.NewFactory(uf), pf)
rf := resmap.NewFactory(resource.NewFactory(uf))
v := validator.NewKustValidator()
c.AddCommand(
build.NewCmdBuild(
stdOut, fSys, v,
rf, pf),
rf, transformer.NewFactoryImpl()),
edit.NewCmdEdit(fSys, v, uf),
misc.NewCmdConfig(fSys),
misc.NewCmdVersion(stdOut),

View File

@@ -54,18 +54,15 @@ type Kunstructured interface {
MarshalJSON() ([]byte, error)
UnmarshalJSON([]byte) error
GetGvk() gvk.Gvk
SetGvk(gvk.Gvk)
GetKind() string
GetName() string
SetName(string)
SetNamespace(string)
GetLabels() map[string]string
SetLabels(map[string]string)
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
MatchesLabelSelector(selector string) (bool, error)
MatchesAnnotationSelector(selector string) (bool, error)
Patch(Kunstructured) error
}
// KunstructuredFactory makes instances of Kunstructured.

View File

@@ -0,0 +1,17 @@
/// 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)
}

View File

@@ -49,7 +49,7 @@ func NewKustTestHarnessFull(
t *testing.T, path string,
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
rf := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), transformer.NewFactoryImpl())
kunstruct.NewKunstructuredFactoryImpl()))
return &KustTestHarness{
t: t,
rf: rf,

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package test
package plugins
import (
"io/ioutil"
@@ -12,14 +12,13 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/pgmconfig"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
// EnvForTest manages the plugin test environment.
// It sets/resets XDG_CONFIG_HOME, makes/removes a temp objRoot.
type EnvForTest struct {
t *testing.T
compiler *plugins.Compiler
compiler *Compiler
workDir string
oldXdg string
wasSet bool
@@ -62,7 +61,7 @@ func (x *EnvForTest) BuildExecPlugin(g, v, k string) {
}
}
func (x *EnvForTest) makeCompiler() *plugins.Compiler {
func (x *EnvForTest) makeCompiler() *Compiler {
// The plugin loader wants to find object code under
// $XDG_CONFIG_HOME/kustomize/plugins
// and the compiler writes object code to
@@ -74,11 +73,11 @@ func (x *EnvForTest) makeCompiler() *plugins.Compiler {
if err != nil {
x.t.Error(err)
}
srcRoot, err := plugins.DefaultSrcRoot()
srcRoot, err := DefaultSrcRoot()
if err != nil {
x.t.Error(err)
}
return plugins.NewCompiler(srcRoot, objRoot)
return NewCompiler(srcRoot, objRoot)
}
func (x *EnvForTest) createWorkDir() {

View File

@@ -30,7 +30,7 @@ func TestExecPluginConfig(t *testing.T) {
path := "/app"
rf := resmap.NewFactory(
resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
kunstruct.NewKunstructuredFactoryImpl()))
ldr := loadertest.NewFakeLoader(path)
pluginConfig := rf.RF().FromMap(
map[string]interface{}{

View File

@@ -9,7 +9,6 @@ import (
"sigs.k8s.io/kustomize/v3/internal/loadertest"
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
. "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/resource"
)
@@ -42,7 +41,7 @@ port: "12345"
)
func TestLoader(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -51,7 +50,7 @@ func TestLoader(t *testing.T) {
"someteam.example.com", "v1", "SomeServiceGenerator")
rmF := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
kunstruct.NewKunstructuredFactoryImpl()))
l := NewLoader(ActivePluginConfig(), rmF)
if l == nil {

View File

@@ -14,12 +14,11 @@ import (
// Factory makes instances of ResMap.
type Factory struct {
resF *resource.Factory
tf PatchFactory
}
// NewFactory returns a new resmap.Factory.
func NewFactory(rf *resource.Factory, tf PatchFactory) *Factory {
return &Factory{resF: rf, tf: tf}
func NewFactory(rf *resource.Factory) *Factory {
return &Factory{resF: rf}
}
// RF returns a resource.Factory.
@@ -119,11 +118,6 @@ func (rmF *Factory) FromSecretArgs(
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) {
result := New()
for _, res := range resources {

View File

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

View File

@@ -112,18 +112,13 @@ type ResMap interface {
// match.
GetById(resid.ResId) (*resource.Resource, error)
// GroupedByCurrentNamespace returns a map of namespace
// GroupedByNamespace returns a map of namespace
// to a slice of *Resource in that namespace.
// Resources for whom IsNamespaceableKind is false are
// are not included at all (see NonNamespaceable).
// Resources with an empty namespace are placed
// in the resid.DefaultNamespace entry.
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
GroupedByNamespace() map[string][]*resource.Resource
// NonNamespaceable returns a slice of resources that
// cannot be placed in a namespace, e.g.
@@ -395,19 +390,19 @@ func demandOneMatch(
return nil, fmt.Errorf("no matches for %sId %s", s, id)
}
// GroupedByCurrentNamespace implements ResMap.GroupByCurrentNamespace
func (m *resWrangler) GroupedByCurrentNamespace() map[string][]*resource.Resource {
items := m.groupedByCurrentNamespace()
// GroupedByNamespace implements ResMap.GroupByNamespace
func (m *resWrangler) GroupedByNamespace() map[string][]*resource.Resource {
items := m.groupedByNamespace()
delete(items, resid.TotallyNotANamespace)
return items
}
// NonNamespaceable implements ResMap.NonNamespaceable
func (m *resWrangler) NonNamespaceable() []*resource.Resource {
return m.groupedByCurrentNamespace()[resid.TotallyNotANamespace]
return m.groupedByNamespace()[resid.TotallyNotANamespace]
}
func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resource {
func (m *resWrangler) groupedByNamespace() map[string][]*resource.Resource {
byNamespace := make(map[string][]*resource.Resource)
for _, res := range m.rList {
namespace := res.CurId().EffectiveNamespace()
@@ -419,25 +414,6 @@ func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resourc
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.
func (m *resWrangler) AsYaml() ([]byte, error) {
firstObj := true
@@ -554,20 +530,7 @@ func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
inputRes *resource.Resource) ResMap {
inputId := inputRes.OrgId()
if !inputId.IsNamespaceableKind() {
if inputRes.GetOutermostNamePrefix() == "" {
return m
}
result := New()
for _, r := range m.Resources() {
if r.GetOutermostNamePrefix() == inputRes.GetOutermostNamePrefix() &&
r.GetOutermostNameSuffix() == inputRes.GetOutermostNameSuffix() {
err := result.Append(r)
if err != nil {
panic(err)
}
}
}
return result
return m
}
result := New()
for _, r := range m.Resources() {

View File

@@ -19,7 +19,7 @@ import (
var rf = resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
var rmF = NewFactory(rf, nil)
var rmF = NewFactory(rf)
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
err := w.Append(r)

View File

@@ -62,14 +62,6 @@ func (rm *rmBuilder) AddWithNs(ns string, m map[string]interface{}) *rmBuilder {
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 {
r := rm.rf.FromMap(m)
_, err := rm.m.Replace(r)

View File

@@ -43,11 +43,6 @@ func (rf *Factory) FromMapWithNamespace(n string, m map[string]interface{}) *Res
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.
func (rf *Factory) FromMapAndOption(
m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *Resource {

View File

@@ -42,7 +42,6 @@ func (r *Resource) Replace(other *Resource) {
r.SetAnnotations(
mergeStringMaps(other.GetAnnotations(), r.GetAnnotations()))
r.SetName(other.GetName())
r.SetNamespace(other.GetNamespace())
r.copyOtherFields(other)
}
@@ -127,7 +126,7 @@ func (r *Resource) GetOutermostNameSuffix() string {
}
func (r *Resource) InSameFuzzyNamespace(o *Resource) bool {
return r.CurId().IsNsEquals(o.CurId()) &&
return r.GetNamespace() == o.GetNamespace() &&
r.GetOutermostNamePrefix() == o.GetOutermostNamePrefix() &&
r.GetOutermostNameSuffix() == o.GetOutermostNameSuffix()
}

View File

@@ -8,10 +8,10 @@
package target_test
import (
"sigs.k8s.io/kustomize/v3/pkg/plugins"
"testing"
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
)
// 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
// in for the test.
func TestChartInflatorPlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(

View File

@@ -9,8 +9,8 @@ import (
"strings"
"testing"
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
const patchAddProbe = `
@@ -340,7 +340,7 @@ patchesStrategicMerge:
}
func TestIssue1251_Plugins_ProdVsDev(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -380,7 +380,7 @@ transformers:
}
func TestIssue1251_Plugins_Local(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -430,7 +430,7 @@ jsonOp: '%s'
// Remote in the sense that they are bundled in a different kustomization.
func TestIssue1251_Plugins_Bundled(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@ import (
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/v3/pkg/accumulator"
"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/plugins"
"sigs.k8s.io/kustomize/v3/pkg/resmap"
@@ -29,7 +30,7 @@ type KustTarget struct {
kustomization *types.Kustomization
ldr ifc.Loader
rFactory *resmap.Factory
tFactory resmap.PatchFactory
tFactory transformer.Factory
pLdr *plugins.Loader
}
@@ -37,7 +38,7 @@ type KustTarget struct {
func NewKustTarget(
ldr ifc.Loader,
rFactory *resmap.Factory,
tFactory resmap.PatchFactory,
tFactory transformer.Factory,
pLdr *plugins.Loader) (*KustTarget, error) {
content, err := loadKustFile(ldr)
if err != nil {
@@ -292,7 +293,19 @@ func (kt *KustTarget) configureExternalGenerators() ([]transformers.Generator, e
}
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
t, err := kt.tFactory.MakePatchTransformer(patches, kt.rFactory.RF())
if err != nil {
return err
}
r = append(r, t)
tConfig := ra.GetTransformerConfig()
lts, err := kt.configureBuiltinTransformers(tConfig)
if err != nil {
@@ -304,7 +317,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
return err
}
r = append(r, lts...)
t := transformers.NewMultiTransformer(r)
t = transformers.NewMultiTransformer(r)
return ra.Transform(t)
}

View File

@@ -63,8 +63,6 @@ func (kt *KustTarget) configureBuiltinTransformers(
// with tests:
// - patch SMP
configurators := []transformerConfigurator{
kt.configureBuiltinPatchStrategicMergeTransformer,
kt.configureBuiltinPatchTransformer,
kt.configureBuiltinNamespaceTransformer,
kt.configureBuiltinNameTransformer,
kt.configureBuiltinLabelTransformer,
@@ -167,52 +165,6 @@ func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
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(
tConfig *config.TransformerConfig) (
result []transformers.Transformer, err error) {

View File

@@ -61,8 +61,6 @@ spec:
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
- name: sidecar
image: sidecar:latest
volumes:
- name: nginx-persistent-storage
emptyDir: {}
@@ -140,6 +138,8 @@ spec:
env:
- name: ANOTHERENV
value: FOO
- name: sidecar
image: sidecar
volumes:
- name: nginx-persistent-storage
`)
@@ -187,7 +187,7 @@ spec:
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
- image: sidecar:latest
- image: sidecar
name: sidecar
volumes:
- gcePersistentDisk:
@@ -293,258 +293,3 @@ spec:
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
`)
}

View File

@@ -87,43 +87,3 @@ metadata:
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
`)
}

View File

@@ -5,6 +5,7 @@ package target_test
import (
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
"strings"
"testing"
)
@@ -50,46 +51,19 @@ resources:
- role.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
// This validates Fix #1444. This should not be an error anymore -
_, err := th.MakeKustTarget().MakeCustomizedResMap()
// TODO: Fix #1044
// This should not be an error -
// the secrets have the same name but are in different namespaces.
// The ClusterRole (by def) is not in a namespace,
// an in this case applies to *any* Secret resource
// named "dummy"
if err != nil {
t.Fatalf("Err: %v", err)
if err == nil {
t.Fatalf("unexpected lack of error")
}
if !strings.Contains(
err.Error(),
"slice case - multiple matches for ~G_v1_Secret|default|dummy") {
t.Fatalf("unexpected error: %s", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: default
type: Opaque
---
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: kube-system
type: Opaque
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dummy
rules:
- apiGroups:
- ""
resourceNames:
- dummy
resources:
- secrets
verbs:
- get
`)
}

View File

@@ -12,10 +12,9 @@ import (
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer"
"sigs.k8s.io/kustomize/v3/pkg/fs"
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
"sigs.k8s.io/kustomize/v3/pkg/loader"
"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/resource"
"sigs.k8s.io/kustomize/v3/pkg/target"
@@ -23,7 +22,7 @@ import (
)
func TestPluginDir(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(
@@ -63,7 +62,7 @@ metadata:
t.Fatalf("Err: %v", err)
}
rf := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
kunstruct.NewKunstructuredFactoryImpl()))
pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf)
tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl)

View File

@@ -15,7 +15,6 @@ func writeBase(th *kusttest_test.KustTestHarness) {
resources:
- serviceaccount.yaml
- rolebinding.yaml
- clusterrolebinding.yaml
namePrefix: pfx-
nameSuffix: -sfx
`)
@@ -35,19 +34,6 @@ roleRef:
kind: Role
name: role
subjects:
- kind: 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: Role
name: role
subjects:
- kind: ServiceAccount
name: serviceaccount
`)
@@ -100,18 +86,6 @@ roleRef:
kind: Role
name: role
subjects:
- kind: ServiceAccount
name: pfx-serviceaccount-sfx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: pfx-rolebinding-sfx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role
subjects:
- kind: ServiceAccount
name: pfx-serviceaccount-sfx
`)
@@ -140,18 +114,6 @@ roleRef:
kind: Role
name: role
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: Role
name: role
subjects:
- kind: ServiceAccount
name: a-pfx-serviceaccount-sfx-suffixA
`)
@@ -180,18 +142,6 @@ roleRef:
kind: Role
name: role
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: Role
name: role
subjects:
- kind: ServiceAccount
name: b-pfx-serviceaccount-sfx-suffixB
`)
@@ -224,18 +174,6 @@ 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: Role
name: role
subjects:
- kind: ServiceAccount
name: a-pfx-serviceaccount-sfx-suffixA
---
apiVersion: v1
kind: ServiceAccount
metadata:
@@ -250,18 +188,6 @@ roleRef:
kind: Role
name: role
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: Role
name: role
subjects:
- kind: ServiceAccount
name: b-pfx-serviceaccount-sfx-suffixB
`)

View File

@@ -7,8 +7,8 @@ import (
"strings"
"testing"
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func writeDeployment(th *kusttest_test.KustTestHarness, path string) {
@@ -50,7 +50,7 @@ metadata:
}
func TestOrderedTransformers(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -96,7 +96,7 @@ spec:
}
func TestPluginsNotEnabled(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -119,7 +119,7 @@ transformers:
}
func TestSedTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(
@@ -187,7 +187,7 @@ metadata:
}
func TestTransformedTransformers(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -52,9 +52,6 @@ nameReference:
- path: spec/initContainers/envFrom/configMapRef/name
version: v1
kind: Pod
- path: spec/volumes/projected/sources/configMap/name
version: v1
kind: Pod
- path: spec/template/spec/volumes/configMap/name
kind: Deployment
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
@@ -77,8 +74,6 @@ nameReference:
kind: ReplicaSet
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
kind: ReplicaSet
- path: spec/template/spec/volumes/projected/sources/configMap/name
kind: ReplicaSet
- path: spec/template/spec/volumes/configMap/name
kind: DaemonSet
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
@@ -89,8 +84,6 @@ nameReference:
kind: DaemonSet
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
kind: DaemonSet
- path: spec/template/spec/volumes/projected/sources/configMap/name
kind: DaemonSet
- path: spec/template/spec/volumes/configMap/name
kind: StatefulSet
- path: spec/template/spec/containers/env/valueFrom/configMapKeyRef/name
@@ -113,8 +106,6 @@ nameReference:
kind: Job
- path: spec/template/spec/initContainers/envFrom/configMapRef/name
kind: Job
- path: spec/template/spec/volumes/projected/sources/configMap/name
kind: Job
- path: spec/jobTemplate/spec/template/spec/volumes/configMap/name
kind: CronJob
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/configMap/name
@@ -149,9 +140,6 @@ nameReference:
- path: spec/imagePullSecrets/name
version: v1
kind: Pod
- path: spec/volumes/projected/sources/secret/name
version: v1
kind: Pod
- path: spec/template/spec/volumes/secret/secretName
kind: Deployment
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
@@ -178,8 +166,6 @@ nameReference:
kind: ReplicaSet
- path: spec/template/spec/imagePullSecrets/name
kind: ReplicaSet
- path: spec/template/spec/volumes/projected/sources/secret/name
kind: ReplicaSet
- path: spec/template/spec/volumes/secret/secretName
kind: DaemonSet
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
@@ -192,8 +178,6 @@ nameReference:
kind: DaemonSet
- path: spec/template/spec/imagePullSecrets/name
kind: DaemonSet
- path: spec/template/spec/volumes/projected/sources/secret/name
kind: DaemonSet
- path: spec/template/spec/volumes/secret/secretName
kind: StatefulSet
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
@@ -220,8 +204,6 @@ nameReference:
kind: Job
- path: spec/template/spec/imagePullSecrets/name
kind: Job
- path: spec/template/spec/volumes/projected/sources/secret/name
kind: Job
- path: spec/jobTemplate/spec/template/spec/volumes/secret/secretName
kind: CronJob
- path: spec/jobTemplate/spec/template/spec/volumes/projected/sources/secret/name
@@ -299,10 +281,10 @@ nameReference:
- kind: ServiceAccount
version: v1
fieldSpecs:
- path: subjects
- path: subjects/name
kind: RoleBinding
group: rbac.authorization.k8s.io
- path: subjects
- path: subjects/name
kind: ClusterRoleBinding
group: rbac.authorization.k8s.io
- path: spec/serviceAccountName
@@ -343,8 +325,6 @@ nameReference:
fieldSpecs:
- path: spec/volumeName
kind: PersistentVolumeClaim
- path: rules/resourceNames
kind: ClusterRole
- kind: StorageClass
version: v1
@@ -354,7 +334,5 @@ nameReference:
kind: PersistentVolume
- path: spec/storageClassName
kind: PersistentVolumeClaim
- path: spec/volumeClaimTemplates/spec/storageClassName
kind: StatefulSet
`
)

View File

@@ -106,102 +106,6 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
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
}
inMap["name"] = newname
if newnamespace != "" {
// We don't want value "" to replace value "default" since
// the empty string is handled as a wild card here not default namespace
// by kubernetes.
inMap["namespace"] = newnamespace
}
return inMap, nil
}
func (o *nameReferenceTransformer) getNewNameFunc(
referrer *resource.Resource,
target gvk.Gvk,
@@ -210,40 +114,52 @@ func (o *nameReferenceTransformer) getNewNameFunc(
switch in.(type) {
case string:
oldName, _ := in.(string)
return o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
for _, res := range referralCandidates.Resources() {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.GvknEquals)
// 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, fmt.Errorf(
"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{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case string:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
oldName, _ := item.(string)
newName, err := o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
if err != nil {
return nil, err
}
l[idx] = newName
case map[string]interface{}:
// Kind: RoleBinding/ClusterRoleBinding
// FieldSpec is subjects
// Note: The corresponding fieldSpec had been changed from
// from path: subjects/name to just path: subjects. This is
// what get mutatefield to request the mapping of the whole
// map containing namespace and name instead of just a simple
// string field containing the name
oldMap, _ := item.(map[string]interface{})
newMap, err := o.getNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
if err != nil {
return nil, err
}
l[idx] = newMap
default:
var names []string
for _, item := range l {
name, ok := item.(string)
if !ok {
return nil, fmt.Errorf(
"%#v is expected to be either a []string or a []map[string]interface{}", in)
"%#v is expected to be %T", item, name)
}
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

View File

@@ -8,8 +8,6 @@ import (
"testing"
"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/resmaptest"
"sigs.k8s.io/kustomize/v3/pkg/resource"
@@ -468,7 +466,6 @@ func TestNameReferenceHappyRun(t *testing.T) {
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)
}
@@ -500,7 +497,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
},
},
}).ResMap(),
expectedErr: "is expected to be"},
expectedErr: "is expected to be string"},
{
resMap: resmaptest_test.NewRmBuilder(t, rf).Add(
map[string]interface{}{
@@ -520,7 +517,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
},
},
}).ResMap(),
expectedErr: "is expected to be"},
expectedErr: "is expected to be either a string or a []interface{}"},
}
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
@@ -593,431 +590,3 @@ func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
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"
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,
},
}}).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,
},
},
}).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).
// 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,
},
}}).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,
},
},
}).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)
}
}

View File

@@ -200,6 +200,7 @@ func (k *Kustomization) EnforceFields() []string {
// new field names.
func FixKustomizationPreUnmarshalling(data []byte) []byte {
deprecateFieldsMap := map[string]string{
"patches:": "patchesStrategicMerge:",
"imageTags:": "images:",
}
for oldname, newname := range deprecateFieldsMap {

View File

@@ -149,7 +149,7 @@ func (p *ImageTagTransformerPlugin) findContainers(obj map[string]interface{}) e
func isImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.-].
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
pattern, _ := regexp.Compile("^" + t + "(:[a-zA-Z0-9_.-]*)?$")
return pattern.MatchString(s)
}
@@ -175,7 +175,7 @@ func split(imageName string) (name string, tag string) {
}
i := ic
if ia > 0 {
if ic < 0 {
i = ia
}

View File

@@ -52,7 +52,6 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
}
}
p.updateClusterRoleBinding(m)
p.updateServiceReference(m)
return nil
}
@@ -126,40 +125,3 @@ func (p *NamespaceTransformerPlugin) updateClusterRoleBinding(m resmap.ResMap) {
objMap["subjects"] = subjects
}
}
func (p *NamespaceTransformerPlugin) updateServiceReference(m resmap.ResMap) {
svc := gvk.Gvk{Version: "v1", Kind: "Service"}
svcMap := map[string]bool{}
for _, id := range m.AllIds() {
if id.Gvk.Equals(svc) {
svcMap[id.Name] = true
}
}
for _, res := range m.Resources() {
if res.OrgId().Kind != "ValidatingWebhookConfiguration" &&
res.OrgId().Kind != "MutatingWebhookConfiguration" {
continue
}
objMap := res.Map()
webhooks, ok := objMap["webhooks"].([]interface{})
if webhooks == nil || !ok {
continue
}
for i := range webhooks {
webhook := webhooks[i].(map[string]interface{})
transformers.MutateField(
webhook, []string{"clientConfig", "service"},
false, func(obj interface{}) (interface{}, error) {
svc := obj.(map[string]interface{})
svcName, foundN := svc["name"]
if foundN && svcMap[svcName.(string)] {
svc["namespace"] = p.Namespace
}
return svc, nil
})
webhooks[i] = webhook
}
objMap["webhooks"] = webhooks
}
}

View File

@@ -1,75 +0,0 @@
// 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
}
}
return nil
}

View File

@@ -1,147 +0,0 @@
// 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
}
}
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))
}

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestAnnotationsTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestConfigMapGenerator(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestHashTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -150,7 +150,7 @@ func (p *plugin) findContainers(obj map[string]interface{}) error {
func isImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.-].
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
pattern, _ := regexp.Compile("^" + t + "(:[a-zA-Z0-9_.-]*)?$")
return pattern.MatchString(s)
}
@@ -176,7 +176,7 @@ func split(imageName string) (name string, tag string) {
}
i := ic
if ia > 0 {
if ic < 0 {
i = ia
}

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestImageTagTransformerNewTag(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
func TestImageTagTransformer(t *testing.T) {
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -36,22 +36,18 @@ metadata:
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
- name: nginx2
image: my-nginx:1.8.0
- name: init-alpine
image: alpine:1.8.0
containers:
- name: ngnix
image: nginx:1.7.9
- name: repliaced-with-digest
image: foobar:1
- name: postgresdb
image: postgres:1.8.0
`)
th.AssertActualEqualsExpected(rm, `
@@ -65,307 +61,14 @@ spec:
spec:
containers:
- image: nginx:v2
name: nginx-tagged
- image: nginx:v2
name: nginx-latest
name: ngnix
- image: foobar:1
name: replaced-with-digest
name: repliaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx:v2
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: my-nginx:1.8.0
name: nginx2
- image: alpine:1.8.0
name: init-alpine
`)

View File

@@ -6,8 +6,8 @@ package main_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
const (
@@ -59,7 +59,7 @@ metadata:
)
func TestInventoryTransformerCollect(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -80,7 +80,7 @@ policy: GarbageCollect
}
func TestInventoryTransformerIgnore(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -101,7 +101,7 @@ policy: GarbageIgnore
}
func TestInventoryTransformerDefaultPolicy(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestLabelTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestLegacyOrderTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -53,7 +53,6 @@ func (p *plugin) Transform(m resmap.ResMap) error {
}
}
p.updateClusterRoleBinding(m)
p.updateServiceReference(m)
return nil
}
@@ -127,40 +126,3 @@ func (p *plugin) updateClusterRoleBinding(m resmap.ResMap) {
objMap["subjects"] = subjects
}
}
func (p *plugin) updateServiceReference(m resmap.ResMap) {
svc := gvk.Gvk{Version: "v1", Kind: "Service"}
svcMap := map[string]bool{}
for _, id := range m.AllIds() {
if id.Gvk.Equals(svc) {
svcMap[id.Name] = true
}
}
for _, res := range m.Resources() {
if res.OrgId().Kind != "ValidatingWebhookConfiguration" &&
res.OrgId().Kind != "MutatingWebhookConfiguration" {
continue
}
objMap := res.Map()
webhooks, ok := objMap["webhooks"].([]interface{})
if webhooks == nil || !ok {
continue
}
for i := range webhooks {
webhook := webhooks[i].(map[string]interface{})
transformers.MutateField(
webhook, []string{"clientConfig", "service"},
false, func(obj interface{}) (interface{}, error) {
svc := obj.(map[string]interface{})
svcName, foundN := svc["name"]
if foundN && svcMap[svcName.(string)] {
svc["namespace"] = p.Namespace
}
return svc, nil
})
webhooks[i] = webhook
}
objMap["webhooks"] = webhooks
}
}

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestNamespaceTransformer1(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -41,11 +41,6 @@ metadata:
namespace: foo
---
apiVersion: v1
kind: Service
metadata:
name: svc1
---
apiVersion: v1
kind: Namespace
metadata:
name: ns1
@@ -77,22 +72,6 @@ subjects:
name: another
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
kind: CustomResourceDefinition
metadata:
@@ -113,12 +92,6 @@ metadata:
namespace: test
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: test
---
apiVersion: v1
kind: Namespace
metadata:
name: ns1
@@ -150,22 +123,6 @@ subjects:
name: another
namespace: random
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: example
webhooks:
- clientConfig:
service:
name: svc1
namespace: test
name: example1
- clientConfig:
service:
name: svc2
namespace: system
name: example2
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
@@ -174,7 +131,7 @@ metadata:
}
func TestNamespaceTransformerClusterLevelKinds(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -8,7 +8,7 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
const target = `
@@ -29,7 +29,7 @@ spec:
`
func TestPatchJson6902TransformerMissingFile(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -58,7 +58,7 @@ path: jsonpatch.json
}
func TestBadPatchJson6902Transformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -87,7 +87,7 @@ jsonOp: 'thisIsNotAPatch'
}
func TestBothEmptyJson6902Transformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -115,7 +115,7 @@ target:
}
func TestBothSpecifiedJson6902Transformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -151,7 +151,7 @@ jsonOp: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "Clust
}
func TestPatchJson6902TransformerFromJsonFile(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -201,7 +201,7 @@ spec:
}
func TestPatchJson6902TransformerFromYamlFile(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
@@ -251,7 +251,7 @@ spec:
}
func TestPatchJson6902TransformerWithInline(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -1,76 +0,0 @@
// 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
}
}
return nil
}

View File

@@ -1,535 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package main_test
import (
"strings"
"testing"
"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
kind: Deployment
spec:
replica: 2
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- name: nginx
image: nginx
`
targetWithNamespace = `
apiVersion: apps/v1
metadata:
name: myDeploy
namespace: namespace1
kind: Deployment
spec:
replica: 2
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- name: nginx
image: nginx
`
targetNoschema = `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
A: X
B: Y
`
)
func TestPatchStrategicMergeTransformerMissingFile(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
_, err := th.RunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- 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 TestBadPatchStrategicMergeTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
_, err := th.RunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
patches: 'thisIsNotAPatch'
`, target)
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(),
"cannot unmarshal string into Go value of type map[string]interface {}") {
t.Fatalf("unexpected err: %v", err)
}
}
func TestBothEmptyPatchStrategicMergeTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
_, err := th.RunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
`, target)
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(), "empty file path and empty patch content") {
t.Fatalf("unexpected err: %v", err)
}
}
func TestPatchStrategicMergeTransformerFromFiles(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
metadata:
labels:
new-label: new-value
replica: 3
`)
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch.yaml
`, target)
th.AssertActualEqualsExpected(rm, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 3
template:
metadata:
labels:
new-label: new-value
old-label: old-value
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestPatchStrategicMergeTransformerWithInline(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
patches: '{"apiVersion": "apps/v1", "metadata": {"name": "myDeploy"}, "kind": "Deployment", "spec": {"replica": 3}}'
`, target)
th.AssertActualEqualsExpected(rm, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 3
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- image: nginx
name: nginx
`)
}
func TestPatchStrategicMergeTransformerMultiplePatches(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch1.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: SOMEENV
value: BAR
`)
th.WriteF("/app/patch2.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ANOTHERENV
value: HELLO
- name: busybox
image: busybox
`)
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch1.yaml
- patch2.yaml
`, target)
th.AssertActualEqualsExpected(rm, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeploy
spec:
replica: 2
template:
metadata:
labels:
old-label: old-value
spec:
containers:
- env:
- name: ANOTHERENV
value: HELLO
- name: SOMEENV
value: BAR
image: nginx:latest
name: nginx
- image: busybox
name: busybox
`)
}
func TestStrategicMergeTransformerMultiplePatchesWithConflicts(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch1.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: SOMEENV
value: BAR
`)
th.WriteF("/app/patch2.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9
env:
- name: ANOTHERENV
value: HELLO
- name: busybox
image: busybox
`)
err := th.ErrorFromLoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch1.yaml
- patch2.yaml
`, target)
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 TestStrategicMergeTransformerWrongNamespace(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch.yaml", `
apiVersion: apps/v1
metadata:
name: myDeploy
namespace: namespace2
kind: Deployment
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: SOMEENV
value: BAR
`)
err := th.ErrorFromLoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch.yaml
`, targetWithNamespace)
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 TestStrategicMergeTransformerNoSchema(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch.yaml", `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B:
C: Z
`)
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch.yaml
`, targetNoschema)
th.AssertActualEqualsExpected(rm, `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
A: X
C: Z
`)
}
func TestStrategicMergeTransformerNoSchemaMultiPatches(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch1.yaml", `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
B:
C: Z
`)
th.WriteF("/app/patch2.yaml", `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
D: W
baz:
hello: world
`)
rm := th.LoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch1.yaml
- patch2.yaml
`, targetNoschema)
th.AssertActualEqualsExpected(rm, `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
A: X
C: Z
D: W
baz:
hello: world
`)
}
func TestStrategicMergeTransformerNoSchemaMultiPatchesWithConflict(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchStrategicMergeTransformer")
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
th.WriteF("/app/patch1.yaml", `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: Z
`)
th.WriteF("/app/patch2.yaml", `
apiVersion: example.com/v1
kind: Foo
metadata:
name: my-foo
spec:
bar:
C: NOT_Z
`)
err := th.ErrorFromLoadAndRunTransformer(`
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: notImportantHere
paths:
- patch1.yaml
- patch2.yaml
`, targetNoschema)
if !strings.Contains(err.Error(), "conflict") {
t.Fatalf("expected error to contain %q but get %v", "conflict", err)
}
}

View File

@@ -1,148 +0,0 @@
// 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
}
}
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))
}

View File

@@ -1,341 +0,0 @@
// 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
`)
}

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestPrefixSuffixTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestReplicaCountTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestSecretGenerator(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestBashedConfigMapPlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(

View File

@@ -11,7 +11,7 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
// This test requires having the helm binary on the PATH.
@@ -19,7 +19,7 @@ import (
// TODO: Download and inflate the chart, and check that
// in for the test.
func TestChartInflator(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestDatePrefixerPlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -8,7 +8,7 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
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) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestSecretsFromDatabasePlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestSedTransformer(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin("someteam.example.com", "v1", "SedTransformer")

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestSomeServiceGeneratorPlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -7,11 +7,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestStringPrefixerPlugin(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(

View File

@@ -10,11 +10,11 @@ import (
"testing"
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
plugins_test "sigs.k8s.io/kustomize/v3/pkg/plugins/test"
"sigs.k8s.io/kustomize/v3/pkg/plugins"
)
func TestValidatorHappy(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")
@@ -49,7 +49,7 @@ metadata:
}
func TestValidatorUnHappy(t *testing.T) {
tc := plugins_test.NewEnvForTest(t).Set()
tc := plugins.NewEnvForTest(t).Set()
defer tc.Reset()
tc.BuildExecPlugin("someteam.example.com", "v1", "Validator")

View File

@@ -75,14 +75,14 @@ git tag -a $version -m "Release $version"
```
### 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
```
This triggers a job in [Google Cloud Build] to
put a new release on the [release page].
### Update release notes
Visit the [release page] and edit the release notes as desired.