mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-15 10:58:18 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa2313c282 | ||
|
|
eeed1954fb | ||
|
|
cd00ce7ab1 | ||
|
|
145d07363f | ||
|
|
33fff655db | ||
|
|
31ab347da2 | ||
|
|
7a48b2ba8e | ||
|
|
876f2a8236 | ||
|
|
9bff2e8883 | ||
|
|
483188ba89 | ||
|
|
672bda0c9c | ||
|
|
49b32473ca | ||
|
|
08400d77a6 | ||
|
|
c912baeb3a | ||
|
|
433733eb0e | ||
|
|
f996ac82c7 | ||
|
|
efcb7cc5a5 | ||
|
|
bf7b57537b | ||
|
|
6b597f8711 | ||
|
|
088739900f | ||
|
|
3bf13f83d3 | ||
|
|
c64a72f1f9 | ||
|
|
8b60b456ac |
@@ -1,5 +1,7 @@
|
||||
# kustomize
|
||||
|
||||
_[v3.0.0](https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.0.0) 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.
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
# 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].
|
||||
@@ -25,15 +30,18 @@ current setup.
|
||||
## Make a place to work
|
||||
|
||||
```
|
||||
# Keeping these separate to avoid cluttering the DEMO dir.
|
||||
DEMO=$(mktemp -d)
|
||||
tmpGoPath=$(mktemp -d)
|
||||
```
|
||||
|
||||
## Install kustomize
|
||||
|
||||
Need v3.0.0 for what follows:
|
||||
Need v3.0.0 for what follows, and you must _compile_
|
||||
it (not download the binary from the release page):
|
||||
|
||||
```
|
||||
GOBIN=$DEMO/bin go get sigs.k8s.io/kustomize/v3/cmd/kustomize@v3.0.0-pre
|
||||
GOPATH=$tmpGoPath go install sigs.k8s.io/kustomize/v3/cmd/kustomize
|
||||
```
|
||||
|
||||
## Make a home for plugins
|
||||
@@ -147,7 +155,7 @@ Build the object code for use by kustomize:
|
||||
|
||||
```
|
||||
cd $MY_PLUGIN_DIR
|
||||
go build -buildmode plugin -o ${kind}.so ${kind}.go
|
||||
GOPATH=$tmpGoPath go build -buildmode plugin -o ${kind}.so ${kind}.go
|
||||
```
|
||||
|
||||
This step may succeed, but kustomize might
|
||||
@@ -199,7 +207,8 @@ cat <<EOF >$MYAPP/secGenerator.yaml
|
||||
apiVersion: ${apiVersion}
|
||||
kind: ${kind}
|
||||
metadata:
|
||||
name: forbiddenValues
|
||||
name: mySecretGenerator
|
||||
name: forbiddenValues
|
||||
namespace: production
|
||||
file: myEncryptedData.yaml
|
||||
keys:
|
||||
@@ -257,7 +266,7 @@ echo $keyLocation
|
||||
### Install `sops`
|
||||
|
||||
```
|
||||
GOBIN=$DEMO/bin go install go.mozilla.org/sops/cmd/sops
|
||||
GOPATH=$tmpGoPath go install go.mozilla.org/sops/cmd/sops
|
||||
```
|
||||
|
||||
### Create data encrypted with your Google Cloud key
|
||||
@@ -270,13 +279,12 @@ ROCKET: saturn-v
|
||||
FRUIT: apple
|
||||
CAR: dymaxion
|
||||
EOF
|
||||
|
||||
```
|
||||
|
||||
Encrypt the data into file the plugin wants to read:
|
||||
|
||||
```
|
||||
$DEMO/bin/sops --encrypt \
|
||||
$tmpGoPath/bin/sops --encrypt \
|
||||
--gcp-kms $keyLocation \
|
||||
$MYAPP/myClearData.yaml >$MYAPP/myEncryptedData.yaml
|
||||
```
|
||||
@@ -287,11 +295,32 @@ Review the files
|
||||
tree $DEMO
|
||||
```
|
||||
|
||||
This should look something like:
|
||||
|
||||
> ```
|
||||
> /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:
|
||||
|
||||
```
|
||||
XDG_CONFIG_HOME=$DEMO $DEMO/bin/kustomize build --enable_alpha_plugins $MYAPP
|
||||
XDG_CONFIG_HOME=$DEMO $tmpGoPath/bin/kustomize build --enable_alpha_plugins $MYAPP
|
||||
```
|
||||
|
||||
This should emit a kubernetes secret, with
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
# kustomize 3.0.0
|
||||
|
||||
This release is basically [v2.1.0](v2.1.0.md),
|
||||
with some post-v2.1.0 bugs fixed and a `v3` in Go
|
||||
package paths.
|
||||
with many post-v2.1.0 bugs fixed (in about 150
|
||||
commits) 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), to carry them
|
||||
through the coming series of minor releases and
|
||||
patches.
|
||||
|
||||
developers who happen to use Go).
|
||||
|
||||
### Why so soon after v2.1.0?
|
||||
|
||||
|
||||
14
go.mod
14
go.mod
@@ -6,10 +6,16 @@ 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
|
||||
@@ -17,10 +23,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-20190809220925-3ab596449d6f
|
||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010
|
||||
k8s.io/client-go v0.0.0-20190812221009-4f902818859a
|
||||
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/klog v0.3.3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058
|
||||
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
|
||||
48
go.sum
48
go.sum
@@ -1,5 +1,3 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
@@ -12,13 +10,9 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.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=
|
||||
@@ -38,40 +32,26 @@ github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88d
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/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=
|
||||
@@ -83,16 +63,13 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-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=
|
||||
@@ -100,13 +77,11 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega 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=
|
||||
@@ -117,27 +92,21 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify 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=
|
||||
@@ -149,22 +118,17 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.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=
|
||||
@@ -175,27 +139,17 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
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/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
||||
@@ -20,6 +20,10 @@ 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"
|
||||
@@ -285,3 +289,59 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,9 +18,8 @@ func NewFactoryImpl() *FactoryImpl {
|
||||
return &FactoryImpl{}
|
||||
}
|
||||
|
||||
// MakePatchTransformer makes a new patch transformer
|
||||
func (p *FactoryImpl) MakePatchTransformer(
|
||||
slice []*resource.Resource,
|
||||
rf *resource.Factory) (transformers.Transformer, error) {
|
||||
return patch.NewTransformer(slice, rf)
|
||||
func (p *FactoryImpl) MergePatches(patches []*resource.Resource,
|
||||
rf *resource.Factory) (
|
||||
resmap.ResMap, error) {
|
||||
return patch.MergePatches(patches, rf)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@ 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"
|
||||
@@ -122,3 +127,64 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/evanphx/json-patch"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
||||
)
|
||||
|
||||
// transformer applies strategic merge patches.
|
||||
type transformer struct {
|
||||
patches []*resource.Resource
|
||||
rf *resource.Factory
|
||||
}
|
||||
|
||||
var _ transformers.Transformer = &transformer{}
|
||||
|
||||
// NewTransformer constructs a strategic merge patch transformer.
|
||||
func NewTransformer(
|
||||
slice []*resource.Resource, rf *resource.Factory) (transformers.Transformer, error) {
|
||||
if len(slice) == 0 {
|
||||
return transformers.NewNoOpTransformer(), nil
|
||||
}
|
||||
return &transformer{patches: slice, rf: rf}, nil
|
||||
}
|
||||
|
||||
// Transform apply the patches on top of the base resources.
|
||||
// nolint:ineffassign
|
||||
func (tf *transformer) Transform(m resmap.ResMap) error {
|
||||
patches, err := tf.mergePatches()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, patch := range patches.Resources() {
|
||||
target, err := m.GetById(patch.OrgId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
merged := map[string]interface{}{}
|
||||
versionedObj, err := scheme.Scheme.New(
|
||||
toSchemaGvk(patch.OrgId().Gvk))
|
||||
saveName := target.GetName()
|
||||
switch {
|
||||
case runtime.IsNotRegisteredError(err):
|
||||
// Use JSON merge patch to handle types w/o schema
|
||||
baseBytes, err := json.Marshal(target.Map())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBytes, err := json.Marshal(patch.Map())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mergedBytes, err := jsonpatch.MergePatch(baseBytes, patchBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(mergedBytes, &merged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case err != nil:
|
||||
return err
|
||||
default:
|
||||
// Use Strategic-Merge-Patch to handle types w/ schema
|
||||
// TODO: Change this to use the new Merge package.
|
||||
// Store the name of the target object, because this name may have been munged.
|
||||
// Apply this name to the patched object.
|
||||
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(
|
||||
target.Map(),
|
||||
patch.Map(),
|
||||
lookupPatchMeta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
target.SetMap(merged)
|
||||
target.SetName(saveName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mergePatches merge and index patches by OrgId.
|
||||
// It errors out if there is conflict between patches.
|
||||
func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
||||
rc := resmap.New()
|
||||
for ix, patch := range tf.patches {
|
||||
id := patch.OrgId()
|
||||
existing := rc.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
||||
if len(existing) == 0 {
|
||||
rc.Append(patch)
|
||||
continue
|
||||
}
|
||||
if len(existing) > 1 {
|
||||
return nil, fmt.Errorf("self conflict in patches")
|
||||
}
|
||||
|
||||
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
|
||||
if err != nil && !runtime.IsNotRegisteredError(err) {
|
||||
return nil, err
|
||||
}
|
||||
var cd conflictDetector
|
||||
if err != nil {
|
||||
cd = newJMPConflictDetector(tf.rf)
|
||||
} else {
|
||||
cd, err = newSMPConflictDetector(versionedObj, tf.rf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
conflict, err := cd.hasConflict(existing[0], patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conflict {
|
||||
conflictingPatch, err := cd.findConflict(ix, tf.patches)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf(
|
||||
"conflict between %#v and %#v",
|
||||
conflictingPatch.Map(), patch.Map())
|
||||
}
|
||||
merged, err := cd.mergePatches(existing[0], patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc.Replace(merged)
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
// toSchemaGvk converts to a schema.GroupVersionKind.
|
||||
func toSchemaGvk(x gvk.Gvk) schema.GroupVersionKind {
|
||||
return schema.GroupVersionKind{
|
||||
Group: x.Group,
|
||||
Version: x.Version,
|
||||
Kind: x.Kind,
|
||||
}
|
||||
}
|
||||
@@ -1,579 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package patch
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||
)
|
||||
|
||||
var rf = resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
|
||||
func TestOverlayRun(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"another-label": "foo",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "SOMEENV",
|
||||
"value": "BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"old-label": "old-value",
|
||||
"another-label": "foo",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "SOMEENV",
|
||||
"value": "BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = expected.ErrorIfNotEqualLists(base)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiplePatches(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "SOMEENV",
|
||||
"value": "BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "ANOTHERENV",
|
||||
"value": "HELLO",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "busybox",
|
||||
"image": "busybox",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "ANOTHERENV",
|
||||
"value": "HELLO",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "SOMEENV",
|
||||
"value": "BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"name": "busybox",
|
||||
"image": "busybox",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = expected.ErrorIfNotEqualLists(base)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiplePatchesWithConflict(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"env": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "SOMEENV",
|
||||
"value": "BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:1.7.9",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err == nil {
|
||||
t.Fatalf("did not get expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "conflict") {
|
||||
t.Fatalf("expected error to contain %q but get %v", "conflict", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchesWithWrongNamespace(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
"namespace": "namespace1",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "deploy1",
|
||||
"namespace": "namespace2",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"template": map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx",
|
||||
"image": "nginx:1.7.9",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err == nil {
|
||||
t.Fatalf("did not get expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "failed to find unique target for patch") {
|
||||
t.Fatalf("expected error to contain %q but get %v", "failed to find target for patch", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSchemaOverlayRun(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"A": "X",
|
||||
"B": "Y",
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"B": nil,
|
||||
"C": "Z",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"A": "X",
|
||||
"C": "Z",
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSchemaMultiplePatches(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"A": "X",
|
||||
"B": "Y",
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"B": nil,
|
||||
"C": "Z",
|
||||
},
|
||||
},
|
||||
}),
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"C": "Z",
|
||||
"D": "W",
|
||||
},
|
||||
"baz": map[string]interface{}{
|
||||
"hello": "world",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"A": "X",
|
||||
"C": "Z",
|
||||
"D": "W",
|
||||
},
|
||||
"baz": map[string]interface{}{
|
||||
"hello": "world",
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) {
|
||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||
Add(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"A": "X",
|
||||
"B": "Y",
|
||||
},
|
||||
},
|
||||
}).ResMap()
|
||||
patch := []*resource.Resource{
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"B": nil,
|
||||
"C": "Z",
|
||||
},
|
||||
},
|
||||
}),
|
||||
rf.FromMap(map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "my-foo",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"bar": map[string]interface{}{
|
||||
"C": "NOT_Z",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
lt, err := NewTransformer(patch, rf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = lt.Transform(base)
|
||||
if err == nil {
|
||||
t.Fatalf("did not get expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "conflict") {
|
||||
t.Fatalf("expected error to contain %q but get %v", "conflict", err)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ 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"
|
||||
@@ -61,7 +60,7 @@ https://github.com/hashicorp/go-getter#url-format
|
||||
func NewCmdBuild(
|
||||
out io.Writer, fSys fs.FileSystem,
|
||||
v ifc.Validator, rf *resmap.Factory,
|
||||
ptf transformer.Factory) *cobra.Command {
|
||||
ptf resmap.PatchFactory) *cobra.Command {
|
||||
var o Options
|
||||
|
||||
pluginConfig := plugins.DefaultPluginConfig()
|
||||
@@ -115,7 +114,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 transformer.Factory,
|
||||
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||
pl *plugins.Loader) error {
|
||||
ldr, err := loader.NewLoader(
|
||||
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
||||
@@ -136,7 +135,7 @@ func (o *Options) RunBuild(
|
||||
|
||||
func (o *Options) RunBuildPrune(
|
||||
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
||||
rf *resmap.Factory, ptf transformer.Factory,
|
||||
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||
pl *plugins.Loader) error {
|
||||
ldr, err := loader.NewLoader(
|
||||
o.loadRestrictor, v, o.kustomizationPath, fSys)
|
||||
@@ -180,7 +179,7 @@ func (o *Options) emitResources(
|
||||
|
||||
func NewCmdBuildPrune(
|
||||
out io.Writer, v ifc.Validator, fSys fs.FileSystem,
|
||||
rf *resmap.Factory, ptf transformer.Factory,
|
||||
rf *resmap.Factory, ptf resmap.PatchFactory,
|
||||
pl *plugins.Loader) *cobra.Command {
|
||||
var o Options
|
||||
|
||||
|
||||
@@ -36,12 +36,13 @@ See https://sigs.k8s.io/kustomize
|
||||
}
|
||||
|
||||
uf := kunstruct.NewKunstructuredFactoryImpl()
|
||||
rf := resmap.NewFactory(resource.NewFactory(uf))
|
||||
pf := transformer.NewFactoryImpl()
|
||||
rf := resmap.NewFactory(resource.NewFactory(uf), pf)
|
||||
v := validator.NewKustValidator()
|
||||
c.AddCommand(
|
||||
build.NewCmdBuild(
|
||||
stdOut, fSys, v,
|
||||
rf, transformer.NewFactoryImpl()),
|
||||
rf, pf),
|
||||
edit.NewCmdEdit(fSys, v, uf),
|
||||
misc.NewCmdConfig(fSys),
|
||||
misc.NewCmdVersion(stdOut),
|
||||
|
||||
@@ -57,12 +57,14 @@ type Kunstructured interface {
|
||||
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.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package patch holds miscellaneous interfaces used by kustomize.
|
||||
package transformer
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
||||
)
|
||||
|
||||
// Factory makes transformers that require k8sdeps.
|
||||
type Factory interface {
|
||||
MakePatchTransformer(
|
||||
slice []*resource.Resource,
|
||||
rf *resource.Factory) (transformers.Transformer, error)
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func NewKustTestHarnessFull(
|
||||
t *testing.T, path string,
|
||||
lr loader.LoadRestrictorFunc, pc *types.PluginConfig) *KustTestHarness {
|
||||
rf := resmap.NewFactory(resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()))
|
||||
kunstruct.NewKunstructuredFactoryImpl()), transformer.NewFactoryImpl())
|
||||
return &KustTestHarness{
|
||||
t: t,
|
||||
rf: rf,
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestExecPluginConfig(t *testing.T) {
|
||||
path := "/app"
|
||||
rf := resmap.NewFactory(
|
||||
resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()))
|
||||
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||
ldr := loadertest.NewFakeLoader(path)
|
||||
pluginConfig := rf.RF().FromMap(
|
||||
map[string]interface{}{
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestLoader(t *testing.T) {
|
||||
"someteam.example.com", "v1", "SomeServiceGenerator")
|
||||
|
||||
rmF := resmap.NewFactory(resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()))
|
||||
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||
|
||||
l := NewLoader(ActivePluginConfig(), rmF)
|
||||
if l == nil {
|
||||
|
||||
@@ -14,11 +14,12 @@ 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) *Factory {
|
||||
return &Factory{resF: rf}
|
||||
func NewFactory(rf *resource.Factory, tf PatchFactory) *Factory {
|
||||
return &Factory{resF: rf, tf: tf}
|
||||
}
|
||||
|
||||
// RF returns a resource.Factory.
|
||||
@@ -118,6 +119,11 @@ 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 {
|
||||
|
||||
15
pkg/resmap/patchfactory.go
Normal file
15
pkg/resmap/patchfactory.go
Normal file
@@ -0,0 +1,15 @@
|
||||
/// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package patch holds miscellaneous interfaces used by kustomize.
|
||||
package resmap
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
||||
)
|
||||
|
||||
// PatchFactory makes transformers that require k8sdeps.
|
||||
type PatchFactory interface {
|
||||
MergePatches(patches []*resource.Resource,
|
||||
rf *resource.Factory) (ResMap, error)
|
||||
}
|
||||
@@ -530,7 +530,20 @@ func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||
inputRes *resource.Resource) ResMap {
|
||||
inputId := inputRes.OrgId()
|
||||
if !inputId.IsNamespaceableKind() {
|
||||
return m
|
||||
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
|
||||
}
|
||||
result := New()
|
||||
for _, r := range m.Resources() {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
var rf = resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
var rmF = NewFactory(rf)
|
||||
var rmF = NewFactory(rf, nil)
|
||||
|
||||
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
|
||||
err := w.Append(r)
|
||||
|
||||
@@ -42,6 +42,7 @@ func (r *Resource) Replace(other *Resource) {
|
||||
r.SetAnnotations(
|
||||
mergeStringMaps(other.GetAnnotations(), r.GetAnnotations()))
|
||||
r.SetName(other.GetName())
|
||||
r.SetNamespace(other.GetNamespace())
|
||||
r.copyOtherFields(other)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ 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"
|
||||
@@ -30,7 +29,7 @@ type KustTarget struct {
|
||||
kustomization *types.Kustomization
|
||||
ldr ifc.Loader
|
||||
rFactory *resmap.Factory
|
||||
tFactory transformer.Factory
|
||||
tFactory resmap.PatchFactory
|
||||
pLdr *plugins.Loader
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ type KustTarget struct {
|
||||
func NewKustTarget(
|
||||
ldr ifc.Loader,
|
||||
rFactory *resmap.Factory,
|
||||
tFactory transformer.Factory,
|
||||
tFactory resmap.PatchFactory,
|
||||
pLdr *plugins.Loader) (*KustTarget, error) {
|
||||
content, err := loadKustFile(ldr)
|
||||
if err != nil {
|
||||
@@ -293,19 +292,7 @@ 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 {
|
||||
@@ -317,7 +304,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ func (kt *KustTarget) configureBuiltinTransformers(
|
||||
// with tests:
|
||||
// - patch SMP
|
||||
configurators := []transformerConfigurator{
|
||||
kt.configureBuiltinPatchStrategicMergeTransformer,
|
||||
kt.configureBuiltinNamespaceTransformer,
|
||||
kt.configureBuiltinNameTransformer,
|
||||
kt.configureBuiltinLabelTransformer,
|
||||
@@ -165,6 +166,28 @@ func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
|
||||
return
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPatchStrategicMergeTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||
result = append(result, transformers.NewNoOpTransformer())
|
||||
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) configureBuiltinLabelTransformer(
|
||||
tConfig *config.TransformerConfig) (
|
||||
result []transformers.Transformer, err error) {
|
||||
|
||||
@@ -87,3 +87,43 @@ 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
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ metadata:
|
||||
t.Fatalf("Err: %v", err)
|
||||
}
|
||||
rf := resmap.NewFactory(resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl()))
|
||||
kunstruct.NewKunstructuredFactoryImpl()), nil)
|
||||
|
||||
pl := plugins.NewLoader(plugins.ActivePluginConfig(), rf)
|
||||
tg, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), pl)
|
||||
|
||||
@@ -15,6 +15,7 @@ func writeBase(th *kusttest_test.KustTestHarness) {
|
||||
resources:
|
||||
- serviceaccount.yaml
|
||||
- rolebinding.yaml
|
||||
- clusterrolebinding.yaml
|
||||
namePrefix: pfx-
|
||||
nameSuffix: -sfx
|
||||
`)
|
||||
@@ -34,6 +35,19 @@ 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
|
||||
`)
|
||||
@@ -86,6 +100,18 @@ 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
|
||||
`)
|
||||
@@ -114,6 +140,18 @@ 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
|
||||
`)
|
||||
@@ -142,6 +180,18 @@ 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
|
||||
`)
|
||||
@@ -174,6 +224,18 @@ 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:
|
||||
@@ -188,6 +250,18 @@ 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
|
||||
`)
|
||||
|
||||
@@ -52,6 +52,9 @@ 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
|
||||
@@ -74,6 +77,8 @@ 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
|
||||
@@ -84,6 +89,8 @@ 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
|
||||
@@ -106,6 +113,8 @@ 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
|
||||
@@ -140,6 +149,9 @@ 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
|
||||
@@ -166,6 +178,8 @@ 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
|
||||
@@ -178,6 +192,8 @@ 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
|
||||
@@ -204,6 +220,8 @@ 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
|
||||
|
||||
@@ -52,6 +52,7 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
}
|
||||
p.updateClusterRoleBinding(m)
|
||||
p.updateServiceReference(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -125,3 +126,40 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
75
plugin/builtin/PatchStrategicMergeTransformer.go
Normal file
75
plugin/builtin/PatchStrategicMergeTransformer.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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
|
||||
}
|
||||
@@ -53,6 +53,7 @@ func (p *plugin) Transform(m resmap.ResMap) error {
|
||||
}
|
||||
}
|
||||
p.updateClusterRoleBinding(m)
|
||||
p.updateServiceReference(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -126,3 +127,40 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ metadata:
|
||||
namespace: foo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ns1
|
||||
@@ -72,6 +77,22 @@ 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:
|
||||
@@ -92,6 +113,12 @@ metadata:
|
||||
namespace: test
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc1
|
||||
namespace: test
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ns1
|
||||
@@ -123,6 +150,22 @@ 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:
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,535 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||
)
|
||||
|
||||
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.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.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.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.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.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.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.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.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.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.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.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)
|
||||
}
|
||||
}
|
||||
@@ -75,14 +75,14 @@ git tag -a $version -m "Release $version"
|
||||
```
|
||||
|
||||
### trigger the cloud build
|
||||
|
||||
Pushing the tag will trigger a job in [Google Cloud
|
||||
Build] to put a new release on the [releases page].
|
||||
|
||||
Push the tag:
|
||||
```
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user