mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-30 09:51:23 +00:00
Compare commits
2603 Commits
cmd/config
...
api/v0.10.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326a57a9cc | ||
|
|
9dfdebc6c7 | ||
|
|
b896e04c20 | ||
|
|
6ecae1ad50 | ||
|
|
9abb72e4d6 | ||
|
|
6365b3d0cf | ||
|
|
33c2ea01c4 | ||
|
|
863ff0ef1b | ||
|
|
a5117083ec | ||
|
|
a143688a1d | ||
|
|
0676d0bd11 | ||
|
|
b6cb6c8ae9 | ||
|
|
b16e4ec566 | ||
|
|
cb1cbbe044 | ||
|
|
86fb408b2c | ||
|
|
ca5d691199 | ||
|
|
394567079d | ||
|
|
e0c8ebc41f | ||
|
|
8668691ade | ||
|
|
374d790a21 | ||
|
|
d8f406d06f | ||
|
|
46b3cd2109 | ||
|
|
20c608989a | ||
|
|
ba4d83f75f | ||
|
|
067559127d | ||
|
|
37ab5579f0 | ||
|
|
ef5f1d347d | ||
|
|
2c4b195516 | ||
|
|
04396ab4e6 | ||
|
|
4fd77b3a6e | ||
|
|
3ea8b79925 | ||
|
|
71b978da1a | ||
|
|
7110298c52 | ||
|
|
b4a69f08c0 | ||
|
|
572d5841c6 | ||
|
|
984a2dab3d | ||
|
|
c3c02887ec | ||
|
|
ba051c863b | ||
|
|
4d59146e48 | ||
|
|
5765ab4dbc | ||
|
|
4769751943 | ||
|
|
e506ce021e | ||
|
|
ed763991de | ||
|
|
55ac9ca88d | ||
|
|
548f5ffca9 | ||
|
|
dd3377b1a0 | ||
|
|
605239a1e5 | ||
|
|
67c58ad4f4 | ||
|
|
11e19a3d0f | ||
|
|
6fffcb9203 | ||
|
|
68790e00a9 | ||
|
|
6cf06fac12 | ||
|
|
0d8c107362 | ||
|
|
f30e45c549 | ||
|
|
250ea13767 | ||
|
|
608128738d | ||
|
|
7153f33466 | ||
|
|
274b12318d | ||
|
|
94c82f61a3 | ||
|
|
d260f50573 | ||
|
|
40c014a991 | ||
|
|
75c8aec29d | ||
|
|
fcb9c0065e | ||
|
|
63ec6bdb3d | ||
|
|
25bfe6f306 | ||
|
|
635c4fd43b | ||
|
|
c455215f55 | ||
|
|
8f56f51307 | ||
|
|
70a8ed6ed3 | ||
|
|
febfaf16dc | ||
|
|
8268b17700 | ||
|
|
0889995a61 | ||
|
|
4e476ae574 | ||
|
|
7efd7d23fe | ||
|
|
6fb944815b | ||
|
|
5e3432fbbe | ||
|
|
f0c6bd7773 | ||
|
|
dd579c905d | ||
|
|
22b735885a | ||
|
|
b7c5058e37 | ||
|
|
baff5f4359 | ||
|
|
dce4ea5846 | ||
|
|
c47fc48607 | ||
|
|
1d9b6cbe57 | ||
|
|
1cb93123fc | ||
|
|
c6cb42ec27 | ||
|
|
67a5f6d68f | ||
|
|
e997cc5486 | ||
|
|
53577a5190 | ||
|
|
c1ae234a64 | ||
|
|
02cb395ec2 | ||
|
|
65e7529ca0 | ||
|
|
f70743b267 | ||
|
|
f4382738ab | ||
|
|
a100dca303 | ||
|
|
50414208d1 | ||
|
|
e17a007719 | ||
|
|
dd3c5f5c0a | ||
|
|
fb3f560e0c | ||
|
|
12c177a365 | ||
|
|
402f6ca72b | ||
|
|
2b8a39373e | ||
|
|
17f18604e4 | ||
|
|
99e404cb61 | ||
|
|
d4e3b4f832 | ||
|
|
6552b90657 | ||
|
|
bf57d698b1 | ||
|
|
4d002af735 | ||
|
|
2bfc7cc1b0 | ||
|
|
0244f0919e | ||
|
|
f122fb12f3 | ||
|
|
f7cd553044 | ||
|
|
7d0b7e2113 | ||
|
|
c3a67cfdca | ||
|
|
4315e982be | ||
|
|
634464353f | ||
|
|
9c36004493 | ||
|
|
1b1034442c | ||
|
|
a89863c84c | ||
|
|
f7340e0615 | ||
|
|
bf6b207cc9 | ||
|
|
f93b4877f7 | ||
|
|
cd17338759 | ||
|
|
c46867c3a7 | ||
|
|
3c321ef79c | ||
|
|
7938fdb596 | ||
|
|
a2111869e6 | ||
|
|
f8288e2f02 | ||
|
|
f2f90d1185 | ||
|
|
459e800ecf | ||
|
|
8f00d3fd53 | ||
|
|
cd94cb13c6 | ||
|
|
e100be620e | ||
|
|
1e1b9b484a | ||
|
|
3e7246690f | ||
|
|
360585dfaf | ||
|
|
f604619dd5 | ||
|
|
0fa056327a | ||
|
|
6db2bf69f3 | ||
|
|
20fb9578c0 | ||
|
|
4eb8232495 | ||
|
|
6c4e8019f8 | ||
|
|
28707bf5df | ||
|
|
023a580f00 | ||
|
|
a2eaae5555 | ||
|
|
75df1a5422 | ||
|
|
f0b4cc4581 | ||
|
|
7a41e479c9 | ||
|
|
3350c7213c | ||
|
|
7b5e43d343 | ||
|
|
06661ea310 | ||
|
|
38b2b33503 | ||
|
|
f735d6fb3a | ||
|
|
5cb5e07ac0 | ||
|
|
54778504ed | ||
|
|
1bfe0d08dc | ||
|
|
56da9a58fc | ||
|
|
54383bca25 | ||
|
|
88461b4fed | ||
|
|
aabbea3e78 | ||
|
|
adedca09f2 | ||
|
|
9a27a9f19f | ||
|
|
3ebdb3fcef | ||
|
|
97e7cb1512 | ||
|
|
262a2d9288 | ||
|
|
91b862b556 | ||
|
|
b8ffc725c7 | ||
|
|
76f1411922 | ||
|
|
d1003d6f8f | ||
|
|
91f74e8d16 | ||
|
|
94c5096a95 | ||
|
|
f35aeb6a8e | ||
|
|
d6ce846047 | ||
|
|
ec069e4f19 | ||
|
|
c5adafd9ce | ||
|
|
16dcc98cff | ||
|
|
59c410a70a | ||
|
|
9b586162d0 | ||
|
|
803885049b | ||
|
|
be4fe7540e | ||
|
|
927568eea2 | ||
|
|
436d5e717c | ||
|
|
d37fa66ebc | ||
|
|
e8a4bf6edc | ||
|
|
35d1c3f9b4 | ||
|
|
e17785af21 | ||
|
|
0537b59f27 | ||
|
|
339e33d2f3 | ||
|
|
f082ac02cf | ||
|
|
9538ae1258 | ||
|
|
34981b664f | ||
|
|
477d8930e0 | ||
|
|
b5091a566a | ||
|
|
9981c45554 | ||
|
|
0f736ec7fd | ||
|
|
7826ad1e06 | ||
|
|
f4e6816338 | ||
|
|
4a13725678 | ||
|
|
ab9b010856 | ||
|
|
29be7fabe4 | ||
|
|
74e867833a | ||
|
|
91dc6d2a0f | ||
|
|
3c1fd0e9cf | ||
|
|
4deeb7d59b | ||
|
|
89b12cfc62 | ||
|
|
c07ffa5c1e | ||
|
|
259fcfcef8 | ||
|
|
f81201b74d | ||
|
|
6dbc74b32e | ||
|
|
ed38b5fe2b | ||
|
|
a84badb834 | ||
|
|
e1804cbc76 | ||
|
|
d13eef7951 | ||
|
|
0b4c6baf44 | ||
|
|
b3af54340c | ||
|
|
8c14b9d1af | ||
|
|
d818ccae92 | ||
|
|
4cea8b9785 | ||
|
|
84a36801e0 | ||
|
|
6eb7b3508d | ||
|
|
2a5f4ac7d7 | ||
|
|
518a16d3ac | ||
|
|
d53a2ad45d | ||
|
|
bb02a7645b | ||
|
|
5a9d90c872 | ||
|
|
4fd7269643 | ||
|
|
1eb3c1a075 | ||
|
|
a1746f2f8c | ||
|
|
b727febd08 | ||
|
|
c819d69ae4 | ||
|
|
bb6f83fb96 | ||
|
|
02d14d724a | ||
|
|
aa92d83d8c | ||
|
|
5427ab7cc3 | ||
|
|
e583f199b8 | ||
|
|
b465c20f65 | ||
|
|
5c2c617ff0 | ||
|
|
3ab0665c19 | ||
|
|
4b66043735 | ||
|
|
979f03e76c | ||
|
|
c8b049f57f | ||
|
|
f3d8883046 | ||
|
|
e308f321d3 | ||
|
|
beea785ead | ||
|
|
95c5b686be | ||
|
|
0ddf68cc8a | ||
|
|
4cadad5cfe | ||
|
|
9e4a6397d6 | ||
|
|
2e8a3b7c45 | ||
|
|
276d0430bf | ||
|
|
1aa7a1e709 | ||
|
|
78737f5a38 | ||
|
|
dac84d867e | ||
|
|
217e5c7268 | ||
|
|
936ac37a2e | ||
|
|
cb4f5c3983 | ||
|
|
1801d33287 | ||
|
|
b01da61d83 | ||
|
|
23e28bb18a | ||
|
|
a1f1c2d32f | ||
|
|
10331d9560 | ||
|
|
60038d44f9 | ||
|
|
24d06f83ca | ||
|
|
e76638f98d | ||
|
|
ef1b9d4854 | ||
|
|
3c0f805674 | ||
|
|
324581594c | ||
|
|
7fae7d1bd6 | ||
|
|
0af3a75708 | ||
|
|
d39d7db9ed | ||
|
|
a04a6de0ef | ||
|
|
69a6708f9b | ||
|
|
c19a972739 | ||
|
|
2e674337b3 | ||
|
|
727e24f365 | ||
|
|
7e8ba62e9f | ||
|
|
fe60d0c403 | ||
|
|
2e0556b544 | ||
|
|
479acac581 | ||
|
|
3b37fed24b | ||
|
|
8fdb3f1703 | ||
|
|
95e242353b | ||
|
|
199802a176 | ||
|
|
065432e074 | ||
|
|
62fd36facb | ||
|
|
f121e74744 | ||
|
|
5aa2f534be | ||
|
|
86dd74fd62 | ||
|
|
218da9858f | ||
|
|
cebda58437 | ||
|
|
6a82437bc9 | ||
|
|
6b9e8eb891 | ||
|
|
615984bf2d | ||
|
|
bc6ac8a68a | ||
|
|
39f24ef8d2 | ||
|
|
24294d3bd0 | ||
|
|
234fcbfc02 | ||
|
|
b54093ebca | ||
|
|
db307a7084 | ||
|
|
a0c7997b66 | ||
|
|
7458a53a73 | ||
|
|
cf6e6ca4db | ||
|
|
e847ec7474 | ||
|
|
440026b9b3 | ||
|
|
64331ad845 | ||
|
|
294070b3ab | ||
|
|
cabbea0d97 | ||
|
|
732a8522df | ||
|
|
8f82c4c748 | ||
|
|
d0bc25f339 | ||
|
|
ed3200e4f5 | ||
|
|
a3ed120efb | ||
|
|
f1b191c02f | ||
|
|
1493b24b46 | ||
|
|
5993eae1aa | ||
|
|
3e506eae02 | ||
|
|
0305860078 | ||
|
|
0205090e0d | ||
|
|
6adefe4562 | ||
|
|
da1bd901b4 | ||
|
|
636b9c7aeb | ||
|
|
942f112ef5 | ||
|
|
03bbb076bf | ||
|
|
e468d6b4d2 | ||
|
|
57206a628d | ||
|
|
f061bb887b | ||
|
|
75fd9a43a3 | ||
|
|
58165dfc89 | ||
|
|
0e8257c387 | ||
|
|
62e78f8349 | ||
|
|
84724a3ebf | ||
|
|
23544e0431 | ||
|
|
b1fda3d62e | ||
|
|
b8ae69b748 | ||
|
|
4014440d06 | ||
|
|
74b0b3adc6 | ||
|
|
382f09a126 | ||
|
|
f9afdc5c95 | ||
|
|
5e4fb4796e | ||
|
|
76f8988865 | ||
|
|
fa3e829eb6 | ||
|
|
d9435bd1b1 | ||
|
|
af96bb4bda | ||
|
|
8607e0adec | ||
|
|
5a2a7709a4 | ||
|
|
437e8f90f6 | ||
|
|
06ac670951 | ||
|
|
3ee1579688 | ||
|
|
5954314b98 | ||
|
|
c0324456a7 | ||
|
|
172adc404f | ||
|
|
501748192b | ||
|
|
f6e6ac0320 | ||
|
|
a10ce1d787 | ||
|
|
839cc2467c | ||
|
|
dbc11ed29f | ||
|
|
0f614e92f7 | ||
|
|
afaf7c62bc | ||
|
|
78d22069d7 | ||
|
|
22720a8b7a | ||
|
|
38c66d213a | ||
|
|
871de80544 | ||
|
|
c24daec480 | ||
|
|
0849d12572 | ||
|
|
23bd8ff749 | ||
|
|
b5759305af | ||
|
|
da518668b5 | ||
|
|
51605beb3b | ||
|
|
2646861a4c | ||
|
|
f8c910bd3b | ||
|
|
cb82dced8a | ||
|
|
f618f9ce96 | ||
|
|
020dc9c216 | ||
|
|
a6b9445702 | ||
|
|
36408a120c | ||
|
|
c1bca9cd62 | ||
|
|
701973b73e | ||
|
|
24a64bdee3 | ||
|
|
3f3d3b17a4 | ||
|
|
53c87a32e9 | ||
|
|
0fdf0f825f | ||
|
|
73da51d0ac | ||
|
|
df10d5a17d | ||
|
|
9557888b32 | ||
|
|
3e14a31312 | ||
|
|
dca13a4770 | ||
|
|
017a094438 | ||
|
|
b8e7cf04b6 | ||
|
|
a8dacdaffc | ||
|
|
5c4e363f11 | ||
|
|
1e3ce57077 | ||
|
|
01ddeb476d | ||
|
|
714af0cd66 | ||
|
|
82abd7e9ea | ||
|
|
823ff2d048 | ||
|
|
fcfdf6be51 | ||
|
|
627118c438 | ||
|
|
5bb7364967 | ||
|
|
a46926c1eb | ||
|
|
4f760a0850 | ||
|
|
e905411207 | ||
|
|
1eb77a6cab | ||
|
|
8b1704bcf3 | ||
|
|
a0edb2d966 | ||
|
|
02dff45d7d | ||
|
|
3cf18adae9 | ||
|
|
2bec25b46e | ||
|
|
8ee308d5d6 | ||
|
|
3c3c97f9b5 | ||
|
|
c3e8f6008e | ||
|
|
660847225d | ||
|
|
48d16f877b | ||
|
|
a4f4945455 | ||
|
|
bd7229ea17 | ||
|
|
72441ce3ef | ||
|
|
fe5b7a3b41 | ||
|
|
a4db686b6c | ||
|
|
10026758d3 | ||
|
|
c8dddac5b9 | ||
|
|
5a8a4d47a5 | ||
|
|
6c35c06f3e | ||
|
|
1235047742 | ||
|
|
6c041c3a79 | ||
|
|
1e7260b69a | ||
|
|
1de5fe608f | ||
|
|
6c9bf58e7f | ||
|
|
accd71a105 | ||
|
|
e3fd691459 | ||
|
|
3a508da641 | ||
|
|
a64a1022e6 | ||
|
|
b6fba0ad5c | ||
|
|
45fc67062e | ||
|
|
32cef014bb | ||
|
|
677ec868e0 | ||
|
|
7716b1bd3d | ||
|
|
8a529ca399 | ||
|
|
914a82bfa4 | ||
|
|
197c95f6ef | ||
|
|
323672bc38 | ||
|
|
66ce6f8801 | ||
|
|
6bc9d7358c | ||
|
|
bcbfa069ae | ||
|
|
7e622e1382 | ||
|
|
a2871181fe | ||
|
|
86c3863bc9 | ||
|
|
14d2f4bb15 | ||
|
|
c6f575ce37 | ||
|
|
e86fd7f009 | ||
|
|
d03a5ab95f | ||
|
|
8ef9f75de7 | ||
|
|
cf3a125940 | ||
|
|
8049f7b1af | ||
|
|
985fe4821d | ||
|
|
c828b1e49a | ||
|
|
d5d44ce3fe | ||
|
|
5d3dac04fa | ||
|
|
d2f5fe13aa | ||
|
|
705c6ad5ce | ||
|
|
94f8d4ec63 | ||
|
|
225bae8491 | ||
|
|
53f78260a9 | ||
|
|
06add3ab35 | ||
|
|
a59ec8fe23 | ||
|
|
f93cee9440 | ||
|
|
21e65990c1 | ||
|
|
38e9c34f08 | ||
|
|
038bc7713b | ||
|
|
a5914abad8 | ||
|
|
3f2b98ff01 | ||
|
|
aa1dd9ddc2 | ||
|
|
5ba45f1ef8 | ||
|
|
f3752dc75c | ||
|
|
d5f4da1261 | ||
|
|
7680392d96 | ||
|
|
d8015d3c93 | ||
|
|
7487e2f9cb | ||
|
|
4b8bc7d6ba | ||
|
|
59af49522e | ||
|
|
72d3eb15e0 | ||
|
|
14e31de6b1 | ||
|
|
162b8f3d37 | ||
|
|
003cf61a48 | ||
|
|
74f0df8b9d | ||
|
|
0df531e7c6 | ||
|
|
e3ce61647f | ||
|
|
768132f65f | ||
|
|
6a708bcc23 | ||
|
|
d8182f8d81 | ||
|
|
99b6a5920e | ||
|
|
8877c81468 | ||
|
|
88911bbb61 | ||
|
|
82ff64c374 | ||
|
|
01c477570a | ||
|
|
f8dad80a79 | ||
|
|
240cda089a | ||
|
|
c94c193b5b | ||
|
|
9989b5fc84 | ||
|
|
aeba50488b | ||
|
|
9c43518a15 | ||
|
|
9d50890174 | ||
|
|
3af1ae4159 | ||
|
|
5100568b0c | ||
|
|
aa5b4814d6 | ||
|
|
264b3ff338 | ||
|
|
a40c74e545 | ||
|
|
f61b075d3b | ||
|
|
629d822604 | ||
|
|
bf64f109b9 | ||
|
|
5f93fc53f4 | ||
|
|
0fe3f303e8 | ||
|
|
7825050b18 | ||
|
|
ed688a87e4 | ||
|
|
629fdee26a | ||
|
|
ca58ce775a | ||
|
|
0990d96c52 | ||
|
|
94c45e0f9f | ||
|
|
ca527a8e4c | ||
|
|
fa0b237178 | ||
|
|
a9bcf7187a | ||
|
|
a49d429909 | ||
|
|
c63288024d | ||
|
|
f374a12f24 | ||
|
|
c7156d0586 | ||
|
|
d3b7d3ab70 | ||
|
|
197bb9d9e3 | ||
|
|
fa96878cfc | ||
|
|
558995536d | ||
|
|
3255c73c71 | ||
|
|
fd486c1f23 | ||
|
|
b0a40e2752 | ||
|
|
ccb95ab269 | ||
|
|
e6b52e7295 | ||
|
|
4a6ec9063d | ||
|
|
c3beadacd9 | ||
|
|
5f3bd4b4c2 | ||
|
|
e77c284924 | ||
|
|
5ed2067be9 | ||
|
|
7b38ce4ef2 | ||
|
|
700a112b28 | ||
|
|
e05ce0f05b | ||
|
|
b8cfa3ca9b | ||
|
|
26a8455717 | ||
|
|
710db98dbf | ||
|
|
0d152c4784 | ||
|
|
1729c95135 | ||
|
|
6f6d41f17f | ||
|
|
3ff5263ff6 | ||
|
|
5bb668533f | ||
|
|
eb48b1b718 | ||
|
|
1f837fdfec | ||
|
|
1301384670 | ||
|
|
a9c20a2eb7 | ||
|
|
297bdc3825 | ||
|
|
831f99c95b | ||
|
|
5247aa5750 | ||
|
|
74d5646526 | ||
|
|
2f6a611e62 | ||
|
|
d0dbc3e87b | ||
|
|
235101a614 | ||
|
|
123a5d6e56 | ||
|
|
e4bbd04a43 | ||
|
|
75120b2a92 | ||
|
|
cb423ad300 | ||
|
|
c81b5bd3c2 | ||
|
|
b3cec39c25 | ||
|
|
5fc6cab49f | ||
|
|
c636ee616b | ||
|
|
f96ac2d61e | ||
|
|
a513c56d88 | ||
|
|
ed3ab9f532 | ||
|
|
bab8c34c1f | ||
|
|
839fd2b971 | ||
|
|
26e9b8b3b8 | ||
|
|
ddfb4ff02d | ||
|
|
a5e6295923 | ||
|
|
e2e495027d | ||
|
|
397744f436 | ||
|
|
9e8e7a7fe9 | ||
|
|
4d66f9a093 | ||
|
|
81cac9b633 | ||
|
|
43edc6dd7f | ||
|
|
f313cca52b | ||
|
|
243e7cca1f | ||
|
|
b9c36caa1c | ||
|
|
711b4ff4bb | ||
|
|
8d72528eb5 | ||
|
|
6590cce5c1 | ||
|
|
12c0360ba3 | ||
|
|
8e8fa5409d | ||
|
|
5af35f4f1a | ||
|
|
412e73cf76 | ||
|
|
ec27642e2f | ||
|
|
7165b1ec40 | ||
|
|
6dd50de7a4 | ||
|
|
a8b851f84a | ||
|
|
9c4966ccc8 | ||
|
|
d0bb1cd0fa | ||
|
|
102cf87f36 | ||
|
|
584a6c2a86 | ||
|
|
03c6f8fff4 | ||
|
|
90de9b78df | ||
|
|
34f1f2967e | ||
|
|
9a9df7436e | ||
|
|
c036830c70 | ||
|
|
ebbd0c7b5a | ||
|
|
7264a3a65d | ||
|
|
f3a958bbf7 | ||
|
|
14bf6f8a27 | ||
|
|
60c8a0498b | ||
|
|
774d768e7b | ||
|
|
efef397acf | ||
|
|
5793653630 | ||
|
|
4ee3d05bd8 | ||
|
|
a1df3e030f | ||
|
|
4e0332551a | ||
|
|
216ab488a6 | ||
|
|
722b0131f0 | ||
|
|
93dd571df9 | ||
|
|
a7000dd9c6 | ||
|
|
5c4b5b1bf0 | ||
|
|
8e57ee9111 | ||
|
|
60bd8d15d9 | ||
|
|
1d524b6fbe | ||
|
|
e9c97a4c4e | ||
|
|
48c89cb698 | ||
|
|
af1e692a5e | ||
|
|
57e7db0423 | ||
|
|
7fb6fa0f35 | ||
|
|
50c3875354 | ||
|
|
efc03bf329 | ||
|
|
9785bda7be | ||
|
|
29bfdfc1ef | ||
|
|
4f72cb8d00 | ||
|
|
a45e90b1e4 | ||
|
|
6b6bc45f2c | ||
|
|
e4a34f2a48 | ||
|
|
4a2ed901b3 | ||
|
|
ba67bc0f18 | ||
|
|
be8d60fb9f | ||
|
|
d9d5bb83f0 | ||
|
|
cfa7645d3b | ||
|
|
2e6ef91a7c | ||
|
|
508f294e0c | ||
|
|
a81ebe9842 | ||
|
|
c92fb809c6 | ||
|
|
043e8c36e5 | ||
|
|
7965195c29 | ||
|
|
4263d18c1a | ||
|
|
827fb1e1da | ||
|
|
03c77cee9b | ||
|
|
2db34e7127 | ||
|
|
821b14bfd1 | ||
|
|
33b4735f98 | ||
|
|
bbebd1e56a | ||
|
|
c9d9348944 | ||
|
|
555c4cb279 | ||
|
|
3da90dbde7 | ||
|
|
4ac0f59b8a | ||
|
|
2b9c69f964 | ||
|
|
437c960d86 | ||
|
|
131aba8f14 | ||
|
|
ada02703cf | ||
|
|
f96dfb5772 | ||
|
|
57b3e70cef | ||
|
|
f4fbcc6fb4 | ||
|
|
867da9631a | ||
|
|
cd2b0fce7e | ||
|
|
66504c263c | ||
|
|
bce4f75fc5 | ||
|
|
8b082aff5a | ||
|
|
48e4cad72e | ||
|
|
30e53a992b | ||
|
|
2df9f85a20 | ||
|
|
01733d970a | ||
|
|
ac178c539c | ||
|
|
61dcb3f548 | ||
|
|
6f15b1e56d | ||
|
|
9a94c5ecd3 | ||
|
|
2ba148d9b5 | ||
|
|
5a0e193002 | ||
|
|
3265f64cd5 | ||
|
|
c2b1ab8303 | ||
|
|
7dd0ade0f9 | ||
|
|
316e4314ed | ||
|
|
324353eaf6 | ||
|
|
6361c3b1b7 | ||
|
|
f7d13ade35 | ||
|
|
99e82890e1 | ||
|
|
4a35bfa84c | ||
|
|
27f28d5fe0 | ||
|
|
c04cf01b45 | ||
|
|
5614852b33 | ||
|
|
4f23ae5e1a | ||
|
|
3bd088a77c | ||
|
|
fe30a9321a | ||
|
|
c715b82ad7 | ||
|
|
44d308cbba | ||
|
|
c9e7f627fe | ||
|
|
00fa7e636c | ||
|
|
c7a504c9cf | ||
|
|
516ff1fa56 | ||
|
|
81562a7a37 | ||
|
|
ba0baa828c | ||
|
|
420f03d429 | ||
|
|
6cf48442df | ||
|
|
8cf7bc67bb | ||
|
|
48d6af6e38 | ||
|
|
0309a0fb07 | ||
|
|
d7b29455ab | ||
|
|
a414f75f1b | ||
|
|
1c3832f897 | ||
|
|
3ec62c6e26 | ||
|
|
c7ee4c281e | ||
|
|
471ff0c4bb | ||
|
|
cd0d416a11 | ||
|
|
4a1a2bfdd8 | ||
|
|
8d75824bb6 | ||
|
|
232e615afe | ||
|
|
50bfa0564c | ||
|
|
d0b101dc90 | ||
|
|
526ae9ff57 | ||
|
|
b553997447 | ||
|
|
66b7c5968b | ||
|
|
003b4946a2 | ||
|
|
2d7b6a57ca | ||
|
|
ecda4f423e | ||
|
|
9dc4004fbe | ||
|
|
a815774e5e | ||
|
|
f170af70fd | ||
|
|
6518393f5d | ||
|
|
dd72ea1e6a | ||
|
|
dbbe340b4f | ||
|
|
38b30b0edc | ||
|
|
10f9a5afda | ||
|
|
8a61bff299 | ||
|
|
52fbe73d49 | ||
|
|
17ecec2f0a | ||
|
|
aeb6024e72 | ||
|
|
e33addc16b | ||
|
|
2db4121c6a | ||
|
|
d203c2328a | ||
|
|
ec0e42709a | ||
|
|
abae65d8f1 | ||
|
|
054f18701a | ||
|
|
c764bc1618 | ||
|
|
2d2fbe9f14 | ||
|
|
7073371c1a | ||
|
|
dc25a6a1ce | ||
|
|
602ad8aa98 | ||
|
|
1fa3b224b1 | ||
|
|
5a328ababf | ||
|
|
3ae1aa7cd7 | ||
|
|
703fee93af | ||
|
|
3e4a59c1cd | ||
|
|
f98edf1b55 | ||
|
|
e41d94ddef | ||
|
|
0508c89b4b | ||
|
|
e653cffab6 | ||
|
|
e036f85b71 | ||
|
|
cee1324d18 | ||
|
|
b062ce0f66 | ||
|
|
fbcb15b15f | ||
|
|
8eb062637f | ||
|
|
2fe85be932 | ||
|
|
44edfa87fe | ||
|
|
bbccee0219 | ||
|
|
7cdc6cbe2f | ||
|
|
264bfa8998 | ||
|
|
041181afe4 | ||
|
|
5db79285a7 | ||
|
|
556692c9f5 | ||
|
|
71f4cecb4c | ||
|
|
d4d5fca2a5 | ||
|
|
811e1dca05 | ||
|
|
09bc6e76b1 | ||
|
|
065b14c5c5 | ||
|
|
adb2f2237a | ||
|
|
024bbd0777 | ||
|
|
ca1929abfb | ||
|
|
a13ef4da65 | ||
|
|
81ec59fa62 | ||
|
|
075a2d6c0f | ||
|
|
1df430255a | ||
|
|
94d06e1e18 | ||
|
|
c3b240639d | ||
|
|
4de6db3d59 | ||
|
|
58216d1d33 | ||
|
|
4c456d60a4 | ||
|
|
582bc4de01 | ||
|
|
a167084ccf | ||
|
|
a3a11bf3f4 | ||
|
|
4e96502ec6 | ||
|
|
1ae8303bdc | ||
|
|
41df2bed1f | ||
|
|
1f1304194d | ||
|
|
4157933c8d | ||
|
|
a79253e02f | ||
|
|
3b35b121b3 | ||
|
|
3c94d20599 | ||
|
|
1faeb91cc4 | ||
|
|
9f1ef993a1 | ||
|
|
55d8cb3d3a | ||
|
|
a684592639 | ||
|
|
386d10834b | ||
|
|
af32126e80 | ||
|
|
b0cfa15b9c | ||
|
|
62e7df6812 | ||
|
|
c077ed4b58 | ||
|
|
156beb300c | ||
|
|
25b02d2d6c | ||
|
|
781098843e | ||
|
|
af3ffa7059 | ||
|
|
9d7b8952a0 | ||
|
|
cb400c895e | ||
|
|
9a8dcf6a8e | ||
|
|
384b71b5f5 | ||
|
|
4345cd2ade | ||
|
|
1460d13d50 | ||
|
|
97a2b15be6 | ||
|
|
f927cf0b8e | ||
|
|
cbb121e651 | ||
|
|
447b315a61 | ||
|
|
b3cb61b80f | ||
|
|
b9f05dd357 | ||
|
|
1ee16d9f52 | ||
|
|
43157f5d35 | ||
|
|
cd918483f9 | ||
|
|
f71854a0c8 | ||
|
|
6246262965 | ||
|
|
d3ea87220b | ||
|
|
61daea0202 | ||
|
|
a54cd12b39 | ||
|
|
11ce6363b4 | ||
|
|
4de26ccf9d | ||
|
|
7801830152 | ||
|
|
aae2be1a79 | ||
|
|
79e15c05d5 | ||
|
|
507244e6f8 | ||
|
|
3892e3c910 | ||
|
|
dcb26d0901 | ||
|
|
f5f1a15226 | ||
|
|
64644643d4 | ||
|
|
4d1eebbb82 | ||
|
|
b3a9314e27 | ||
|
|
86168cebbc | ||
|
|
57a53797d3 | ||
|
|
f5beffe394 | ||
|
|
4287e28ff4 | ||
|
|
a5cdd98414 | ||
|
|
16a49c50c4 | ||
|
|
a6f29f2bf7 | ||
|
|
22fcf3b3fa | ||
|
|
a31b846fa5 | ||
|
|
22fb23071b | ||
|
|
382cf5c2e0 | ||
|
|
8d4508a041 | ||
|
|
4d5657f037 | ||
|
|
5958edda14 | ||
|
|
48676fe34b | ||
|
|
a8278b6da9 | ||
|
|
31d6e24fa4 | ||
|
|
25e11e9020 | ||
|
|
d8e2a76ef3 | ||
|
|
cff7bd4eb2 | ||
|
|
58db58202c | ||
|
|
fc29d7e108 | ||
|
|
ae060cc225 | ||
|
|
9b4fdcf35a | ||
|
|
bb2d63ab58 | ||
|
|
b5012385c8 | ||
|
|
659a7de8f9 | ||
|
|
866dbf2017 | ||
|
|
ef89df6123 | ||
|
|
97f23966af | ||
|
|
5059033b13 | ||
|
|
d91e8af702 | ||
|
|
1bef8c4cdd | ||
|
|
9b87f78511 | ||
|
|
eda827c317 | ||
|
|
be57e1f6c2 | ||
|
|
021c3ce3fc | ||
|
|
4f184e8ce3 | ||
|
|
2e0d6d42bf | ||
|
|
6cf6eb9f76 | ||
|
|
ffed8f1430 | ||
|
|
3d17503329 | ||
|
|
7ac37867dc | ||
|
|
d8f2d2256d | ||
|
|
463b776486 | ||
|
|
d28ce28130 | ||
|
|
4f72faeecb | ||
|
|
29814b556b | ||
|
|
d94ed369fa | ||
|
|
0cf18987d7 | ||
|
|
a6374db2cb | ||
|
|
e98eada736 | ||
|
|
8a65ece956 | ||
|
|
4cdc3b0bad | ||
|
|
40bf89abcd | ||
|
|
7f548eddd0 | ||
|
|
86e9983bb7 | ||
|
|
cbbcfde99d | ||
|
|
304a9e57ee | ||
|
|
f23f26aa05 | ||
|
|
720857623f | ||
|
|
065c2b861a | ||
|
|
2a16af80bf | ||
|
|
81d324c68c | ||
|
|
b8702561ef | ||
|
|
ea039b36bc | ||
|
|
561cef1d5c | ||
|
|
62c5e424a6 | ||
|
|
45b1bf17d3 | ||
|
|
11dce34407 | ||
|
|
550a89295a | ||
|
|
8083b3607f | ||
|
|
cb42142161 | ||
|
|
cb59e0ef5f | ||
|
|
1a4a9fcdaf | ||
|
|
eb8dc5e20a | ||
|
|
0fb30a1010 | ||
|
|
fdfdfa9e4d | ||
|
|
6042aca7a4 | ||
|
|
94962c8bac | ||
|
|
f6ddea435c | ||
|
|
a9d4b7615f | ||
|
|
822cac26f9 | ||
|
|
97eedc8a43 | ||
|
|
2cb972de3b | ||
|
|
79d0d6b5e1 | ||
|
|
fabaf35c72 | ||
|
|
e13f8803eb | ||
|
|
64ffbcb15d | ||
|
|
b41df2293b | ||
|
|
e3fcec122a | ||
|
|
1edf9b630c | ||
|
|
7c6bf2e21d | ||
|
|
b3fc306f6a | ||
|
|
e92d048af2 | ||
|
|
f76059b824 | ||
|
|
bb41d018b5 | ||
|
|
cf8815b0a0 | ||
|
|
64beee22e9 | ||
|
|
79afd219a5 | ||
|
|
c68cf40d75 | ||
|
|
c7337a7d87 | ||
|
|
875e265e5d | ||
|
|
bdbfb28139 | ||
|
|
d54bc674f2 | ||
|
|
bd4580d73a | ||
|
|
ea5d08bac5 | ||
|
|
14a1a0e4a8 | ||
|
|
497e8038a3 | ||
|
|
44b5acad51 | ||
|
|
e5e19f7c09 | ||
|
|
a03843dfc7 | ||
|
|
b7cce27d40 | ||
|
|
126f5481f3 | ||
|
|
30dcf38609 | ||
|
|
1a2779b2c3 | ||
|
|
658b62c6f1 | ||
|
|
cf0bb49610 | ||
|
|
c2fbb709da | ||
|
|
1a002005c1 | ||
|
|
4f468fcc90 | ||
|
|
769f65d6c4 | ||
|
|
378eaedc82 | ||
|
|
6f2f401f6b | ||
|
|
614e853db3 | ||
|
|
33be04db45 | ||
|
|
8c6a9f6495 | ||
|
|
03b2fff0ee | ||
|
|
69cade143f | ||
|
|
90f45651d1 | ||
|
|
1b740034f7 | ||
|
|
a2d8e686de | ||
|
|
ce2ab487a5 | ||
|
|
7439f1809e | ||
|
|
6977c83a83 | ||
|
|
7b9eb05058 | ||
|
|
e2806a09fd | ||
|
|
f30fea4c07 | ||
|
|
8732671919 | ||
|
|
07cada36fa | ||
|
|
0d6b232b49 | ||
|
|
61455fe489 | ||
|
|
c63ed033ad | ||
|
|
455bd0c563 | ||
|
|
9ad4b1ddca | ||
|
|
d529eb8777 | ||
|
|
f7b2f0c067 | ||
|
|
ff6b337ebe | ||
|
|
76f05f3a40 | ||
|
|
d181a73f56 | ||
|
|
979fe3b457 | ||
|
|
bec45093e2 | ||
|
|
c113c41c9c | ||
|
|
99c9edfc3d | ||
|
|
cde6a5741e | ||
|
|
a315eb56ec | ||
|
|
90654b39bf | ||
|
|
24c4c66403 | ||
|
|
2b5029952c | ||
|
|
6a3bb5df44 | ||
|
|
d9623ab307 | ||
|
|
dd1df5a30e | ||
|
|
0e13a9c02b | ||
|
|
eb26d79fa0 | ||
|
|
7f8da385c0 | ||
|
|
1426137883 | ||
|
|
d90d77cdaf | ||
|
|
1ffd790cfb | ||
|
|
454906d093 | ||
|
|
8b97274af3 | ||
|
|
b1056b43cb | ||
|
|
e411942a74 | ||
|
|
6b30b72ebc | ||
|
|
9ddf0fe304 | ||
|
|
8a952a1b26 | ||
|
|
fff484e98b | ||
|
|
e819a2ba9d | ||
|
|
4908654c09 | ||
|
|
586515ebc4 | ||
|
|
735befef19 | ||
|
|
35087ed0cc | ||
|
|
f84f8f28fd | ||
|
|
45e118458c | ||
|
|
1102153ae3 | ||
|
|
338910d36c | ||
|
|
38e9770f40 | ||
|
|
20a4153893 | ||
|
|
51fba009b3 | ||
|
|
002215d719 | ||
|
|
f9d1e800e4 | ||
|
|
82db6cd73d | ||
|
|
3c25584658 | ||
|
|
c32a809dbd | ||
|
|
02be687778 | ||
|
|
c0a754e7b0 | ||
|
|
63e441a673 | ||
|
|
bd27d5f8bb | ||
|
|
0aa250c6e2 | ||
|
|
e269ad4a80 | ||
|
|
9db6b37b88 | ||
|
|
2361b70967 | ||
|
|
d016326877 | ||
|
|
67e445c10b | ||
|
|
76970a6b05 | ||
|
|
66db1df79a | ||
|
|
6442047e52 | ||
|
|
8ac6954de1 | ||
|
|
494977b9d0 | ||
|
|
0a0a6e1018 | ||
|
|
fa69d4ba9d | ||
|
|
36bdcca735 | ||
|
|
c71a4534a0 | ||
|
|
97402f1136 | ||
|
|
1329afa3ca | ||
|
|
60c8f4c594 | ||
|
|
428e25b856 | ||
|
|
8dd6f2b185 | ||
|
|
a3bf3ba608 | ||
|
|
b97e59c57e | ||
|
|
bae3228557 | ||
|
|
cc43a2d732 | ||
|
|
d25e1effb7 | ||
|
|
485b8121d3 | ||
|
|
401118728a | ||
|
|
0f45bd9583 | ||
|
|
97e4353755 | ||
|
|
826b5d9792 | ||
|
|
8c9da15156 | ||
|
|
e18d619c9e | ||
|
|
f8a3c04286 | ||
|
|
1a4c82241a | ||
|
|
81ca271e62 | ||
|
|
72262c5e71 | ||
|
|
125762d94d | ||
|
|
0ecbd5905b | ||
|
|
cb2b376065 | ||
|
|
595e59b919 | ||
|
|
6bbc829593 | ||
|
|
3dd9c6c0b5 | ||
|
|
c04c13a12a | ||
|
|
05eccab823 | ||
|
|
dd946e1343 | ||
|
|
b4ad4b6984 | ||
|
|
13dee68d3b | ||
|
|
e849b160bc | ||
|
|
87987d3382 | ||
|
|
575b4efc18 | ||
|
|
b1a460985c | ||
|
|
e1fd74bb61 | ||
|
|
8a673b82bd | ||
|
|
d2e995b3e2 | ||
|
|
f2e025ea53 | ||
|
|
dade85e40e | ||
|
|
51ba54ad82 | ||
|
|
4144775a3b | ||
|
|
ff9b215ae7 | ||
|
|
cd5ae17335 | ||
|
|
e3d022325b | ||
|
|
e6dc03bea4 | ||
|
|
d08b9c30ee | ||
|
|
f6e5eedee2 | ||
|
|
212b2cff12 | ||
|
|
f66e5bb923 | ||
|
|
23bc91f233 | ||
|
|
9c421c7410 | ||
|
|
c63dfd6772 | ||
|
|
1a5aa63d54 | ||
|
|
1583cef8d9 | ||
|
|
a7c91c37e9 | ||
|
|
c1dca7fdb5 | ||
|
|
724bbe9452 | ||
|
|
deb2b21cbe | ||
|
|
709f499b44 | ||
|
|
dbaa2d6092 | ||
|
|
6445e03d1a | ||
|
|
19ff1b307e | ||
|
|
55f44a29c6 | ||
|
|
1f1873a6ed | ||
|
|
6e3c4ecc72 | ||
|
|
c37c7b6b2c | ||
|
|
42acdcc1d0 | ||
|
|
67db23b24b | ||
|
|
35a19fb8a9 | ||
|
|
a6c2e982f9 | ||
|
|
a053ff6907 | ||
|
|
64201c8352 | ||
|
|
d5ce26e423 | ||
|
|
09497f0830 | ||
|
|
32dd194aca | ||
|
|
4122787bd8 | ||
|
|
485cb3831e | ||
|
|
2ccb73a2a3 | ||
|
|
83377cf597 | ||
|
|
2bf73c60c3 | ||
|
|
4a55a07c14 | ||
|
|
5279ad904b | ||
|
|
736f110f04 | ||
|
|
c9ab1270fa | ||
|
|
bb5fc9086b | ||
|
|
e8c85456cc | ||
|
|
aa9a397808 | ||
|
|
60ea8de5f1 | ||
|
|
56c8df7b85 | ||
|
|
a51e4234c4 | ||
|
|
50cd01e5f7 | ||
|
|
42b082a6b1 | ||
|
|
c3cdd15769 | ||
|
|
c3a8b6f359 | ||
|
|
4af4483e12 | ||
|
|
8f7bcb9b16 | ||
|
|
f54d904766 | ||
|
|
ba91b6f79f | ||
|
|
851acafe32 | ||
|
|
14eac6020f | ||
|
|
e45d667b4d | ||
|
|
cbdf4a0e43 | ||
|
|
aed7e5aaf9 | ||
|
|
ec64ef705b | ||
|
|
1e0eb58bc9 | ||
|
|
fd2fe35863 | ||
|
|
ebdbd81ed8 | ||
|
|
c9d2ae6b49 | ||
|
|
e8c212a10f | ||
|
|
1eb378254a | ||
|
|
0d030e3095 | ||
|
|
f2706dce68 | ||
|
|
f8194bd3c2 | ||
|
|
eb5227680e | ||
|
|
27e89f271f | ||
|
|
626f2f9d1d | ||
|
|
ffda124ca5 | ||
|
|
fd677f635e | ||
|
|
14b1388c6a | ||
|
|
5248fd0cd9 | ||
|
|
b6ae9f80d3 | ||
|
|
2ad502d5a8 | ||
|
|
a5f3d5c823 | ||
|
|
c65875cacc | ||
|
|
82b2d83ede | ||
|
|
7e01aec5a4 | ||
|
|
9e8a84c5ff | ||
|
|
849d5c4a8d | ||
|
|
00352cbc58 | ||
|
|
b88e770b1d | ||
|
|
eda7a9f8d6 | ||
|
|
114b3f4b00 | ||
|
|
6cb339142d | ||
|
|
052a6b4e96 | ||
|
|
4add7eccd0 | ||
|
|
a0a89e1adc | ||
|
|
10fd4b4bbe | ||
|
|
e15ede037d | ||
|
|
32a2f5ffa9 | ||
|
|
4f74203f6c | ||
|
|
5b0cbcb5fb | ||
|
|
2f4c35347e | ||
|
|
be5db09db1 | ||
|
|
a6833bc4c0 | ||
|
|
2ae323bb26 | ||
|
|
7e74271071 | ||
|
|
260e093547 | ||
|
|
47b12fa3dc | ||
|
|
38801cd966 | ||
|
|
c49e177b9c | ||
|
|
486be07e22 | ||
|
|
a12db91a10 | ||
|
|
f7613631d1 | ||
|
|
8a77494c7d | ||
|
|
af25469c8b | ||
|
|
8c4841c28f | ||
|
|
b6a4dd446a | ||
|
|
606654756d | ||
|
|
97c18518ea | ||
|
|
2dca4ab987 | ||
|
|
712276176c | ||
|
|
c610e3a364 | ||
|
|
02e7589323 | ||
|
|
2ae180ca23 | ||
|
|
98900c43f7 | ||
|
|
02b14d919b | ||
|
|
bd0a699ff6 | ||
|
|
02b4b56c60 | ||
|
|
0cac05448b | ||
|
|
e1c3caeba6 | ||
|
|
a25429ae3b | ||
|
|
e557677fed | ||
|
|
59e0b593cf | ||
|
|
3fa906505c | ||
|
|
a823f3043f | ||
|
|
b2ba82a0bd | ||
|
|
a4f22cb84f | ||
|
|
22f41c789a | ||
|
|
966d0a054c | ||
|
|
97f3ac2da1 | ||
|
|
536b69e5dc | ||
|
|
c7aaa18d0c | ||
|
|
a45523bb95 | ||
|
|
376f59f0f6 | ||
|
|
34863346b0 | ||
|
|
9569ca93d9 | ||
|
|
09377ac19c | ||
|
|
a25300dfd6 | ||
|
|
50e9e90b17 | ||
|
|
e3ad472933 | ||
|
|
154f894774 | ||
|
|
4d7600d4ef | ||
|
|
0a0a0ccddc | ||
|
|
2278e01b7f | ||
|
|
abc88c56c4 | ||
|
|
eddd872eca | ||
|
|
febede115e | ||
|
|
a2087f07d4 | ||
|
|
8b9d8a266d | ||
|
|
5557e1ff3c | ||
|
|
1c009ca217 | ||
|
|
bdb59d2cd2 | ||
|
|
b61a115e76 | ||
|
|
66221d17d4 | ||
|
|
c83f256dbe | ||
|
|
fa3caaacee | ||
|
|
0a0a2ed586 | ||
|
|
aff1db13e0 | ||
|
|
ad092cc7a9 | ||
|
|
0a9fc6c8cb | ||
|
|
881d33ac5c | ||
|
|
842e4f5dc5 | ||
|
|
ef612286e4 | ||
|
|
636c9fcddf | ||
|
|
333945d361 | ||
|
|
afff3ce5ab | ||
|
|
71b763888c | ||
|
|
c5cd539b01 | ||
|
|
4b89c2afa2 | ||
|
|
630fc9b973 | ||
|
|
a468743b81 | ||
|
|
e9a74b87e3 | ||
|
|
64f8d2ae38 | ||
|
|
5ab320c216 | ||
|
|
6131f86d23 | ||
|
|
e7609559ce | ||
|
|
c2bdac7a6b | ||
|
|
4cc2c4f623 | ||
|
|
155c42679c | ||
|
|
88239445ce | ||
|
|
d66fc462ec | ||
|
|
6788af083b | ||
|
|
df0576a270 | ||
|
|
f4d8ebb1da | ||
|
|
0acac39640 | ||
|
|
65db82df0c | ||
|
|
68951bb37e | ||
|
|
b18910aa6d | ||
|
|
f780f7a3c2 | ||
|
|
7966386615 | ||
|
|
2130ba72cc | ||
|
|
94d26ba53a | ||
|
|
c53f31ca4f | ||
|
|
b58075cbc3 | ||
|
|
b3e82a2fe7 | ||
|
|
78c26f55b5 | ||
|
|
ec2a6e4e4b | ||
|
|
886f73aa0f | ||
|
|
73d91dda6e | ||
|
|
9f06376ab2 | ||
|
|
e785bab474 | ||
|
|
8f80a898b6 | ||
|
|
fe84d119d6 | ||
|
|
03b847a749 | ||
|
|
9d2f257acf | ||
|
|
129b25ceff | ||
|
|
57f4ea5354 | ||
|
|
ec2cc2d421 | ||
|
|
712eb6d276 | ||
|
|
a04e3a575c | ||
|
|
03e2fed925 | ||
|
|
c37b3b2525 | ||
|
|
ceeba8764f | ||
|
|
04d133a66f | ||
|
|
99aaa80e1d | ||
|
|
1f806b0aa2 | ||
|
|
1f697e3792 | ||
|
|
28cdcc2e46 | ||
|
|
c0ecd1d1ad | ||
|
|
3923c63182 | ||
|
|
9943e74187 | ||
|
|
3b504fa3e5 | ||
|
|
9fb25fc5a7 | ||
|
|
4d99217a7c | ||
|
|
0834e152b2 | ||
|
|
ff276af317 | ||
|
|
3b79944190 | ||
|
|
d8d57eae29 | ||
|
|
c803ca83a4 | ||
|
|
6bed275234 | ||
|
|
8e5df26e4c | ||
|
|
3fed68b694 | ||
|
|
0e59c36d03 | ||
|
|
00fdf71dc3 | ||
|
|
be327e7443 | ||
|
|
be8d2fe016 | ||
|
|
072ae36fe6 | ||
|
|
b5d8b8d258 | ||
|
|
e6b21174f1 | ||
|
|
49094cf999 | ||
|
|
d2c7db6ca0 | ||
|
|
d141f9b973 | ||
|
|
877da8da6d | ||
|
|
8596e63203 | ||
|
|
b2df55e9d7 | ||
|
|
6daf8f8820 | ||
|
|
e75d4fc87d | ||
|
|
9ae07634f2 | ||
|
|
981959ffcf | ||
|
|
dc31321b05 | ||
|
|
64dc3e14ff | ||
|
|
da0893bac0 | ||
|
|
c1747439cd | ||
|
|
f68986827b | ||
|
|
b736b81167 | ||
|
|
0a04b1bb78 | ||
|
|
f7ebaae39e | ||
|
|
08099f0cea | ||
|
|
6fd04dd253 | ||
|
|
9ac97ef91f | ||
|
|
cfbf426174 | ||
|
|
9aafc61c5b | ||
|
|
cd2ebd3046 | ||
|
|
b20e5d7f84 | ||
|
|
13c9a2873e | ||
|
|
fc06283905 | ||
|
|
119d7cadf5 | ||
|
|
cdc6d1fc28 | ||
|
|
49dced2e01 | ||
|
|
76a8f034cb | ||
|
|
52060ac480 | ||
|
|
719532e4df | ||
|
|
70dcc79bf4 | ||
|
|
55b4448862 | ||
|
|
bcaac6f8c1 | ||
|
|
ba4b44db6b | ||
|
|
fd280d0c0b | ||
|
|
1dbf490146 | ||
|
|
62e4df72d3 | ||
|
|
bb77a7c86d | ||
|
|
41abeb85be | ||
|
|
3c86d37148 | ||
|
|
287b38cc87 | ||
|
|
d8d727b1ca | ||
|
|
a81a3d40ce | ||
|
|
52e682489c | ||
|
|
8714ca5a58 | ||
|
|
0490ca163f | ||
|
|
b4947fe8a0 | ||
|
|
9c7b4fddf9 | ||
|
|
5d5b1c2c38 | ||
|
|
cf1aafb121 | ||
|
|
2d4e406a86 | ||
|
|
2a8edd2859 | ||
|
|
a3bc13847c | ||
|
|
944b19ff7c | ||
|
|
f75274bae7 | ||
|
|
62a8a8c57d | ||
|
|
9514f9cd3a | ||
|
|
c1c2725360 | ||
|
|
e9ff26bb1b | ||
|
|
14dc3dfb81 | ||
|
|
44619d5ca2 | ||
|
|
027b7d61ea | ||
|
|
a458ed84f9 | ||
|
|
108f44377d | ||
|
|
dc8439fbfa | ||
|
|
f5353fafa1 | ||
|
|
3d1376bbbc | ||
|
|
b1ea25e86a | ||
|
|
495f6df973 | ||
|
|
a4f1f0841e | ||
|
|
9d0fba81f0 | ||
|
|
92826c6a1e | ||
|
|
7e04be9ec6 | ||
|
|
d954c39ef7 | ||
|
|
176ac5b4fa | ||
|
|
dd696b5cb4 | ||
|
|
501404e403 | ||
|
|
ddf94175ee | ||
|
|
232da9e12b | ||
|
|
8b9ce8eacb | ||
|
|
ee9a4f2526 | ||
|
|
006ce72b2d | ||
|
|
a80bd15bda | ||
|
|
6c63bb2727 | ||
|
|
a7ba93b1d8 | ||
|
|
4a78cd6579 | ||
|
|
b2b8c12203 | ||
|
|
8cc281fad6 | ||
|
|
7346813b8d | ||
|
|
52f3aca22d | ||
|
|
a6a061215f | ||
|
|
7464d8ac8f | ||
|
|
64fda38e2d | ||
|
|
4cefb62d41 | ||
|
|
ccca424234 | ||
|
|
ca45907af0 | ||
|
|
dcf43c7f2b | ||
|
|
1386ec3850 | ||
|
|
de8e16df15 | ||
|
|
222b2d4485 | ||
|
|
e107020bd2 | ||
|
|
430665e984 | ||
|
|
017d5673ba | ||
|
|
f346b9803e | ||
|
|
58092bf66d | ||
|
|
747323efce | ||
|
|
7428e08f93 | ||
|
|
3c8e6d7151 | ||
|
|
43bd2f4cdb | ||
|
|
1dfc9a88a8 | ||
|
|
01beba8697 | ||
|
|
b1e01b238b | ||
|
|
1f595da9ad | ||
|
|
1cf876927d | ||
|
|
a422c935d8 | ||
|
|
1971816663 | ||
|
|
3d1eab872b | ||
|
|
10c1b0c5fa | ||
|
|
4d95cd3630 | ||
|
|
0c169e96e5 | ||
|
|
5baea8400f | ||
|
|
4052cd4fd8 | ||
|
|
21ac400d49 | ||
|
|
351a4a48e4 | ||
|
|
b3cf475024 | ||
|
|
ded25075b1 | ||
|
|
05b8671d17 | ||
|
|
1bfcc81f08 | ||
|
|
3d058830b9 | ||
|
|
bdb53fca9e | ||
|
|
b7265440f8 | ||
|
|
72e1a27177 | ||
|
|
0a1fde1e41 | ||
|
|
ae4618d327 | ||
|
|
aee6ccb05c | ||
|
|
3cd2a0a2f7 | ||
|
|
c96fa7c347 | ||
|
|
ad01d8d34e | ||
|
|
b214fa7d5a | ||
|
|
68f67c183e | ||
|
|
fe5c3a291f | ||
|
|
f38cc4446b | ||
|
|
e695b0534d | ||
|
|
51ecca8f2f | ||
|
|
460c54064c | ||
|
|
50c0200429 | ||
|
|
b1b5a95466 | ||
|
|
3f71c671df | ||
|
|
2ce9c02ada | ||
|
|
3ffc13dd6e | ||
|
|
2fb8603b2a | ||
|
|
1d4b3fa36c | ||
|
|
03ea8f3615 | ||
|
|
74d0d7960e | ||
|
|
ffed4c95b3 | ||
|
|
c59b393fa4 | ||
|
|
fafe24c9df | ||
|
|
d62d8dcade | ||
|
|
ae7f984c71 | ||
|
|
7c8c827a88 | ||
|
|
ff927fd11a | ||
|
|
a4f6fee6c8 | ||
|
|
dd8edb1b01 | ||
|
|
bb42d8aa1b | ||
|
|
bb60c29672 | ||
|
|
c93274c224 | ||
|
|
f5feffbd23 | ||
|
|
e17bab7e55 | ||
|
|
bd534441ce | ||
|
|
85f79edc97 | ||
|
|
4c48a4ff83 | ||
|
|
eb6c715bc3 | ||
|
|
1320e0c3dc | ||
|
|
df0022c985 | ||
|
|
15fc341a13 | ||
|
|
dd90c41f85 | ||
|
|
3a5951563d | ||
|
|
acdfd9a920 | ||
|
|
52016b22dd | ||
|
|
11049fa0bb | ||
|
|
db6c825c05 | ||
|
|
cb7974cf45 | ||
|
|
00111846d3 | ||
|
|
eafa37810b | ||
|
|
0c0cb9aaba | ||
|
|
b51e09d5fe | ||
|
|
c8cd5e55fc | ||
|
|
103d1461a1 | ||
|
|
f02af7a48b | ||
|
|
eba9edd7a6 | ||
|
|
cf38166bd6 | ||
|
|
03498b46b8 | ||
|
|
9fa9c6c30c | ||
|
|
884e35b4c8 | ||
|
|
28787396b2 | ||
|
|
e3cf8987e1 | ||
|
|
551841b789 | ||
|
|
66740dfad6 | ||
|
|
537ff024dd | ||
|
|
cfab28a5ff | ||
|
|
471d5ccf84 | ||
|
|
6a9e75ee0d | ||
|
|
7500764cbf | ||
|
|
544fc60bfe | ||
|
|
0850eae0b9 | ||
|
|
3818cebe33 | ||
|
|
31b395a33f | ||
|
|
ce0dba9217 | ||
|
|
9abd0119e1 | ||
|
|
b6c6cfa7ac | ||
|
|
0c5fc5e694 | ||
|
|
64cbfbe56d | ||
|
|
6a94eb873f | ||
|
|
0bfec6b39b | ||
|
|
9002c338cb | ||
|
|
f86cb6479e | ||
|
|
8285af8cf1 | ||
|
|
5fa1282dcb | ||
|
|
5a0abc8b12 | ||
|
|
3f2508fa94 | ||
|
|
9d992aae68 | ||
|
|
8c906b804f | ||
|
|
4ff4940fa7 | ||
|
|
09aec5694a | ||
|
|
1f917c0499 | ||
|
|
225ffc7cd8 | ||
|
|
eb638cc312 | ||
|
|
7dfb96425e | ||
|
|
6d4c6127c8 | ||
|
|
6aa72b66ef | ||
|
|
f03fdc09cb | ||
|
|
30b6eeb460 | ||
|
|
bf67fcb6d6 | ||
|
|
4ae420cce1 | ||
|
|
87d2187436 | ||
|
|
f1dabbd4fc | ||
|
|
747e05f2a4 | ||
|
|
3514317b3d | ||
|
|
9299821571 | ||
|
|
d91f313137 | ||
|
|
161af9d99c | ||
|
|
b115c95ea1 | ||
|
|
4c75dac10a | ||
|
|
2f8a376ae4 | ||
|
|
20cd4bfef9 | ||
|
|
b314ca185f | ||
|
|
f6c06b58ef | ||
|
|
c45e05b7bd | ||
|
|
76bae738a0 | ||
|
|
98c88805c3 | ||
|
|
0770661b2a | ||
|
|
67d5871e87 | ||
|
|
f98c683915 | ||
|
|
ffe9c9d947 | ||
|
|
4d42ffc7f8 | ||
|
|
d7dc7d911e | ||
|
|
04404ff61b | ||
|
|
f864e15c68 | ||
|
|
29a444fffc | ||
|
|
327035a43a | ||
|
|
ad7fed061e | ||
|
|
cea2986574 | ||
|
|
00f0fd7109 | ||
|
|
1c6481d011 | ||
|
|
f0bc926640 | ||
|
|
11d9ff5690 | ||
|
|
6a0a909e73 | ||
|
|
bd8f0c88e5 | ||
|
|
e5809e49cb | ||
|
|
880009b648 | ||
|
|
d083c7f1d0 | ||
|
|
684ce141de | ||
|
|
5c8c7a043a | ||
|
|
0fe7f65ef2 | ||
|
|
950c1de46d | ||
|
|
fc690f14a8 | ||
|
|
a6e03e4d11 | ||
|
|
60428be5fb | ||
|
|
4d402d4875 | ||
|
|
fbddd264be | ||
|
|
d3c46d3f7c | ||
|
|
dda3984a8f | ||
|
|
f889ca8885 | ||
|
|
341bacb9a2 | ||
|
|
badc1177d9 | ||
|
|
1680cc72c0 | ||
|
|
2f89de86f8 | ||
|
|
ab4e9c718b | ||
|
|
288c03ddca | ||
|
|
5c60285f25 | ||
|
|
6df0a45368 | ||
|
|
8206987580 | ||
|
|
6189ca9798 | ||
|
|
b8c1601a93 | ||
|
|
34d610a38d | ||
|
|
8e4c8464e7 | ||
|
|
43ab7a8e71 | ||
|
|
d2f23a4b8b | ||
|
|
0dc36a4f7c | ||
|
|
678ae12115 | ||
|
|
c4d937322f | ||
|
|
a2adb835b6 | ||
|
|
01b5c4e9da | ||
|
|
5a4e2c2898 | ||
|
|
51719d8089 | ||
|
|
eb4c5dc035 | ||
|
|
e976386931 | ||
|
|
bae9986422 | ||
|
|
e7970d82a8 | ||
|
|
9bdd489c96 | ||
|
|
0f49fef5ed | ||
|
|
8d74b8c3b5 | ||
|
|
39a8798a87 | ||
|
|
980f407552 | ||
|
|
9ca8f4602d | ||
|
|
ba0f583ee5 | ||
|
|
f432f4d75e | ||
|
|
17793abacd | ||
|
|
64cd4ec1d5 | ||
|
|
fb822984e3 | ||
|
|
6d2a737c29 | ||
|
|
6e7713281e | ||
|
|
6a7bb9e33e | ||
|
|
0e9428c8b0 | ||
|
|
c838962432 | ||
|
|
548d10ef08 | ||
|
|
2db8487f02 | ||
|
|
b42f71a20f | ||
|
|
e9824aa749 | ||
|
|
92cc9fc5e1 | ||
|
|
e53b4c9884 | ||
|
|
d4503dfd1e | ||
|
|
e2973f6ecc | ||
|
|
2bf9fc816d | ||
|
|
ff55856c63 | ||
|
|
ceef219eec | ||
|
|
b21699a277 | ||
|
|
2ab85d2f63 | ||
|
|
320545884c | ||
|
|
16bbc2d67e | ||
|
|
6d860e8ace | ||
|
|
80c8a6df61 | ||
|
|
90bc96d9d8 | ||
|
|
2be59aefec | ||
|
|
91b779269f | ||
|
|
e6ea4ad260 | ||
|
|
f5cab0f6e1 | ||
|
|
e39afc9f68 | ||
|
|
3801a29d9b | ||
|
|
39cf4af638 | ||
|
|
9d65dd0786 | ||
|
|
3dced70850 | ||
|
|
4356043582 | ||
|
|
c202be0338 | ||
|
|
9359155418 | ||
|
|
ba22bbe19e | ||
|
|
3e5989ae18 | ||
|
|
fbebd990a4 | ||
|
|
257707d839 | ||
|
|
c1cd872df6 | ||
|
|
646e0b4f61 | ||
|
|
0f67692265 | ||
|
|
6a7afd8694 | ||
|
|
46194b3385 | ||
|
|
904a9dea08 | ||
|
|
30b58e90a3 | ||
|
|
5bdd8657a5 | ||
|
|
893c99da1c | ||
|
|
43980f8586 | ||
|
|
0c8e033c96 | ||
|
|
fa15242719 | ||
|
|
a2e080bf6c | ||
|
|
e91cdb5eba | ||
|
|
ef54f9be5a | ||
|
|
f051acb83c | ||
|
|
bbb046081b | ||
|
|
77b28a986f | ||
|
|
97bc34eb37 | ||
|
|
719380f523 | ||
|
|
640ae9521b | ||
|
|
1dffc7577b | ||
|
|
a0b7288329 | ||
|
|
cc5617c048 | ||
|
|
a77d7e5164 | ||
|
|
40dc90b3b1 | ||
|
|
16229095b3 | ||
|
|
1d91401772 | ||
|
|
007a5327d7 | ||
|
|
24beeb429d | ||
|
|
9b4d4c9d46 | ||
|
|
d5f868c5c7 | ||
|
|
ff3f39d84b | ||
|
|
451c5c32c9 | ||
|
|
faef5714bf | ||
|
|
7833c6edcf | ||
|
|
a1cd23c91d | ||
|
|
e39a5adc00 | ||
|
|
b6900ead22 | ||
|
|
d03cf061e8 | ||
|
|
8293f3002d | ||
|
|
edced4b3f6 | ||
|
|
501684a9c6 | ||
|
|
4e42e1a058 | ||
|
|
b450b624e8 | ||
|
|
0be4a61f64 | ||
|
|
596c39b7bc | ||
|
|
037ac3b134 | ||
|
|
0ff4e53046 | ||
|
|
660f7f9435 | ||
|
|
e6ee03e3e3 | ||
|
|
ca04c874f2 | ||
|
|
cbfef858a0 | ||
|
|
62fbfdfa21 | ||
|
|
5d72fbc6c9 | ||
|
|
bc37ec9d88 | ||
|
|
8619c9aa13 | ||
|
|
5d8722a786 | ||
|
|
0d5552fca6 | ||
|
|
8a8e35f3bb | ||
|
|
25dbe1eaa8 | ||
|
|
2289e7d2e9 | ||
|
|
eb0f484e3d | ||
|
|
d438271263 | ||
|
|
c4c8decb74 | ||
|
|
0590b225c7 | ||
|
|
45131a6d62 | ||
|
|
4dfe3c6296 | ||
|
|
881f358228 | ||
|
|
86c93b9fb7 | ||
|
|
25e30de2d6 | ||
|
|
a8160356bd | ||
|
|
32de6de313 | ||
|
|
501ec38777 | ||
|
|
1b2a966c62 | ||
|
|
bcdbb1a282 | ||
|
|
01f28e6779 | ||
|
|
3f8e3686e2 | ||
|
|
b47e34ea5e | ||
|
|
762e587471 | ||
|
|
6f782ac8c3 | ||
|
|
e5bc644653 | ||
|
|
1bc9225302 | ||
|
|
99d7ad6dc9 | ||
|
|
345dbc83e3 | ||
|
|
8ddf2297e8 | ||
|
|
b407675fc0 | ||
|
|
fd5eeb1645 | ||
|
|
ff5051711f | ||
|
|
51268a5f06 | ||
|
|
1366e0344a | ||
|
|
9be38e815e | ||
|
|
88c318bf46 | ||
|
|
b71b36a213 | ||
|
|
e5a78710aa | ||
|
|
7ee75c33a9 | ||
|
|
2b328eeb36 | ||
|
|
4da40461d3 | ||
|
|
c96a4f3d73 | ||
|
|
45893b2588 | ||
|
|
2f3c89e73f | ||
|
|
eee581462c | ||
|
|
616363ee73 | ||
|
|
0e13eadd7a | ||
|
|
0c37388135 | ||
|
|
5d1352882b | ||
|
|
c469e80cad | ||
|
|
5559601ecb | ||
|
|
01b34c8ea0 | ||
|
|
eba0ffdde2 | ||
|
|
31c59bd7f2 | ||
|
|
bd7d0f864b | ||
|
|
2da8959198 | ||
|
|
dc591f0a10 | ||
|
|
c94f164e66 | ||
|
|
fb216d8af8 | ||
|
|
72207bfa04 | ||
|
|
fe3321d710 | ||
|
|
35b5890e46 | ||
|
|
ca807019f0 | ||
|
|
6420fc4911 | ||
|
|
bd8262630e | ||
|
|
cf5b26db8a | ||
|
|
4b4049e646 | ||
|
|
f211841035 | ||
|
|
efa4587f92 | ||
|
|
873c8c1d17 | ||
|
|
686e97f2fe | ||
|
|
669ae59982 | ||
|
|
868a226e4e | ||
|
|
a2693d0249 | ||
|
|
b7d913b58c | ||
|
|
f199b747e9 | ||
|
|
5a9fbf7da3 | ||
|
|
c18c803d3f | ||
|
|
d59d0401f4 | ||
|
|
83a70f7830 | ||
|
|
6afabf26ae | ||
|
|
2bcece5f1e | ||
|
|
e605391895 | ||
|
|
9de2c6b58e | ||
|
|
b3f147d012 | ||
|
|
fc70e3181f | ||
|
|
8cd7c13fad | ||
|
|
740ec39dd8 | ||
|
|
e6927a2fdf | ||
|
|
083dccfe91 | ||
|
|
b61553e584 | ||
|
|
8cdc97a0dd | ||
|
|
f205641498 | ||
|
|
bfaca2122a | ||
|
|
9482c571f0 | ||
|
|
1ad49de087 | ||
|
|
5e89565930 | ||
|
|
ef713e33ce | ||
|
|
2f7241f4c3 | ||
|
|
34e0ade3e7 | ||
|
|
436c688bd0 | ||
|
|
9d8fbd9f04 | ||
|
|
bb6fb703a0 | ||
|
|
c99bc47c8d | ||
|
|
60422c8090 | ||
|
|
fc83477ec8 | ||
|
|
c9e8631399 | ||
|
|
974e3847dd | ||
|
|
8f4e7e8072 | ||
|
|
4e74947731 | ||
|
|
43b0f2d925 | ||
|
|
efd5f414a8 | ||
|
|
9b8232533f | ||
|
|
bc5859d44b | ||
|
|
5c433ead5e | ||
|
|
feeaa994b7 | ||
|
|
17f935452f | ||
|
|
6faff2d031 | ||
|
|
18a86bd7d6 | ||
|
|
7eac250cf4 | ||
|
|
52083c6e49 | ||
|
|
6f63cf7238 | ||
|
|
de0c8dedc4 | ||
|
|
c23004df79 | ||
|
|
1a44c3c543 | ||
|
|
a9d1182322 | ||
|
|
a3d5628133 | ||
|
|
a563169461 | ||
|
|
729544b9f4 | ||
|
|
69d497ccdd | ||
|
|
c58c142849 | ||
|
|
9ba04e3f7d | ||
|
|
3f842e5e92 | ||
|
|
9fdb3e1e9e | ||
|
|
462dbcb999 | ||
|
|
3e0448f1b7 | ||
|
|
3c3f9a26f6 | ||
|
|
7d7c889285 | ||
|
|
4fe2f9dd5b | ||
|
|
0cb852b98a | ||
|
|
7f5ce3e6f0 | ||
|
|
bf5656b02b | ||
|
|
0ec901a9a9 | ||
|
|
af057a95c5 | ||
|
|
c48e584d1a | ||
|
|
2ee4eec791 | ||
|
|
f06a64e9cc | ||
|
|
51f9a84358 | ||
|
|
07c25eb458 | ||
|
|
ba57cdbd99 | ||
|
|
8a9dc011f4 | ||
|
|
fd196f5d70 | ||
|
|
4c577f6667 | ||
|
|
65fd7c3e6e | ||
|
|
1dff481883 | ||
|
|
d437f67035 | ||
|
|
ee57e9db12 | ||
|
|
a0fdcfe2e3 | ||
|
|
d9fe98a289 | ||
|
|
8b9829f222 | ||
|
|
2114b97969 | ||
|
|
508d193e7a | ||
|
|
e0eb79adcc | ||
|
|
dcab3cbb5f | ||
|
|
8225ca45a8 | ||
|
|
ef924a5c9c | ||
|
|
33b03fce89 | ||
|
|
3907643880 | ||
|
|
b7f7536cfa | ||
|
|
15bc399d5a | ||
|
|
46a6bf0bb4 | ||
|
|
6717bbd36b | ||
|
|
6fccb7fd48 | ||
|
|
370a3d2e74 | ||
|
|
eb7beba8ad | ||
|
|
1e3bc51645 | ||
|
|
92e1d452b7 | ||
|
|
7abedcf87b | ||
|
|
aa991956ef | ||
|
|
c6524f984c | ||
|
|
a70c6b3496 | ||
|
|
166c7f3167 | ||
|
|
10371aa1b5 | ||
|
|
95fb639fa8 | ||
|
|
0f7aae38e3 | ||
|
|
c660fd33ae | ||
|
|
108195185f | ||
|
|
4fbe565b36 | ||
|
|
e9bc2c00c1 | ||
|
|
45eed23b26 | ||
|
|
27b2c7f294 | ||
|
|
03d6229c0b | ||
|
|
71b7b00bd8 | ||
|
|
e9396dca2c | ||
|
|
bc581b70bf | ||
|
|
ac1c31c82b | ||
|
|
c878957d0b | ||
|
|
f9ee578aed | ||
|
|
0b359d0ef0 | ||
|
|
22ee7cbd49 | ||
|
|
7bf9c7002f | ||
|
|
155411f229 | ||
|
|
699cc70a7c | ||
|
|
a63a472024 | ||
|
|
e894756003 | ||
|
|
55f55a5091 | ||
|
|
8401196ef9 | ||
|
|
14edc3890c | ||
|
|
897698fb29 | ||
|
|
ec9ae3d7b0 | ||
|
|
3a828941fa | ||
|
|
b63b5ce7cc | ||
|
|
23bd4390d3 | ||
|
|
21a0fd33a2 | ||
|
|
c6b6dec91f | ||
|
|
9cf4367db7 | ||
|
|
e9c118fd55 | ||
|
|
bfbb1971d4 | ||
|
|
6fabfe963e | ||
|
|
67cdd2e27e | ||
|
|
6c6b5f744d | ||
|
|
7775666c50 | ||
|
|
bdd7ae085e | ||
|
|
ba3e09849a | ||
|
|
236ae29e9a | ||
|
|
5c3bd83252 | ||
|
|
3674e0a91d | ||
|
|
f9631e4bb2 | ||
|
|
c419c1efc3 | ||
|
|
63f9f79fc0 | ||
|
|
33e68c0f97 | ||
|
|
556eb48651 | ||
|
|
5b26c3b4cc | ||
|
|
42e19d610a | ||
|
|
950b1c895f | ||
|
|
ca5feb7751 | ||
|
|
488a88ec6e | ||
|
|
fd3a4a88be | ||
|
|
e6147347a8 | ||
|
|
0b756877e1 | ||
|
|
0f4b5e6787 | ||
|
|
1b531c6ac7 | ||
|
|
f6cac7e7e8 | ||
|
|
fe0577a15f | ||
|
|
f68740be66 | ||
|
|
855ce1a8db | ||
|
|
6a50372dd5 | ||
|
|
5a0228629f | ||
|
|
def00220ce | ||
|
|
d3a7335bbc | ||
|
|
94095a63ff | ||
|
|
42d1f7b792 | ||
|
|
8912c454ff | ||
|
|
d4eb2c9426 | ||
|
|
d2b95fb09a | ||
|
|
298b3c8622 | ||
|
|
c12e95fe06 | ||
|
|
87c7a32ffe | ||
|
|
a7545bdad3 | ||
|
|
622a121042 | ||
|
|
c2ccfd72ad | ||
|
|
6d324d70c4 | ||
|
|
c7bc9d2066 | ||
|
|
9567d7ef16 | ||
|
|
e5b0ceb4e3 | ||
|
|
5fb238a581 | ||
|
|
3ddc9af6c5 | ||
|
|
128e171c20 | ||
|
|
c2681b6fae | ||
|
|
ae5c392319 | ||
|
|
66bcf84682 | ||
|
|
436dada184 | ||
|
|
a689e0c2b4 | ||
|
|
30ae7183a4 | ||
|
|
279a9b673f | ||
|
|
0ac45c65c9 | ||
|
|
d7fb813c16 | ||
|
|
83c5c4d1f1 | ||
|
|
7259d3eb48 | ||
|
|
0e44202c20 | ||
|
|
0d90b769f1 | ||
|
|
7ad2791072 | ||
|
|
6de94548ba | ||
|
|
b1b190227e | ||
|
|
4ceddaa8f4 | ||
|
|
9e64ac5315 | ||
|
|
f24ec14956 | ||
|
|
98a92a6443 | ||
|
|
8bb612889c | ||
|
|
e3ec184e92 | ||
|
|
3019230283 | ||
|
|
69adcf9aaf | ||
|
|
8d543d8483 | ||
|
|
94a55210e1 | ||
|
|
441581b745 | ||
|
|
a066ba9628 | ||
|
|
3a0dd72c88 | ||
|
|
d4ed285fd1 | ||
|
|
4cae8cfe9b | ||
|
|
b044a52a84 | ||
|
|
5607478d8e | ||
|
|
d60cf8ebc5 | ||
|
|
ef04983392 | ||
|
|
2153863355 | ||
|
|
4afab168c5 | ||
|
|
2c52e3a851 | ||
|
|
781e396122 | ||
|
|
cebb1b31ab | ||
|
|
9137d2a39a | ||
|
|
95f4ecd261 | ||
|
|
600d4f2c0b | ||
|
|
6c4c5cf9ad | ||
|
|
5f5b23af58 | ||
|
|
ae5a690146 | ||
|
|
625e011e2b | ||
|
|
01ce33b926 | ||
|
|
a323d78bbc | ||
|
|
69dc34500a | ||
|
|
919bdb84c9 | ||
|
|
178f4e21f0 | ||
|
|
d732a6faab | ||
|
|
f053ca6a5f | ||
|
|
dfc5c32af5 | ||
|
|
80b3f4e00a | ||
|
|
4646bca230 | ||
|
|
57ca8fa321 | ||
|
|
de7fa4bf3a | ||
|
|
af1280ea43 | ||
|
|
0dd191c0f6 | ||
|
|
e20e126d65 | ||
|
|
abf862fff1 | ||
|
|
27cf3981ca | ||
|
|
2c39ff0fa0 | ||
|
|
afc14afe45 | ||
|
|
6e91e0667d | ||
|
|
1aca8b8b9e | ||
|
|
448c060084 | ||
|
|
b3951942e3 | ||
|
|
b78464c8b1 | ||
|
|
9bd4f78288 | ||
|
|
85e9fa94b0 | ||
|
|
c754927112 | ||
|
|
8049c57b72 | ||
|
|
695ec44bf7 | ||
|
|
5b394b2079 | ||
|
|
97c2ac77cd | ||
|
|
3183fcc926 | ||
|
|
0af9ca1266 | ||
|
|
a6111b5c3c | ||
|
|
fdbd1bdbbb | ||
|
|
16baf7a955 | ||
|
|
69aea07c4e | ||
|
|
2250ad3e18 | ||
|
|
c107d1ddff | ||
|
|
e32aa8ddb2 | ||
|
|
b92de5cb80 | ||
|
|
ecfa732a04 | ||
|
|
f17b893dd2 | ||
|
|
09894d3022 | ||
|
|
fd3e84f701 | ||
|
|
22d5d4d2c1 | ||
|
|
145ba0c7ff | ||
|
|
a83433d5cf | ||
|
|
2d496e0efe | ||
|
|
171412cc98 | ||
|
|
68ab3b87d9 | ||
|
|
e9bd11caaa | ||
|
|
a895220743 | ||
|
|
ab2dc7fcb9 | ||
|
|
afde29601a | ||
|
|
be0f1a7fcb | ||
|
|
99d2994b98 | ||
|
|
94101fb7cc | ||
|
|
346071897e | ||
|
|
0772540214 | ||
|
|
6791688f5f | ||
|
|
28307bc435 | ||
|
|
29cadfe8b0 | ||
|
|
68f4f330f5 | ||
|
|
507779c9dc | ||
|
|
062d0f7b75 | ||
|
|
e783af2881 | ||
|
|
f2da1f621f | ||
|
|
294312f2fc | ||
|
|
ff79bd0b31 | ||
|
|
410e300243 | ||
|
|
e994b3b566 | ||
|
|
b39c522cc1 | ||
|
|
dc4bf03da2 | ||
|
|
a158eeaaff | ||
|
|
4cd3944860 | ||
|
|
79a48a8802 | ||
|
|
5a33e90f18 | ||
|
|
e77d1a881f | ||
|
|
343b938c73 | ||
|
|
25186e94af | ||
|
|
e4ba898e20 | ||
|
|
22a6017870 | ||
|
|
e62f1adabf | ||
|
|
7e2d3ff5ab | ||
|
|
fb6830c98a | ||
|
|
52e8a701ac | ||
|
|
160485ef19 | ||
|
|
cea1154cd9 | ||
|
|
4843718a2b | ||
|
|
a0c1979798 | ||
|
|
8576acf1aa | ||
|
|
1e7a764900 | ||
|
|
9b5ce5002a | ||
|
|
0952421800 | ||
|
|
df9af1869f | ||
|
|
dbb16dcb6d | ||
|
|
cc8fc99999 | ||
|
|
0f0efe2a4c | ||
|
|
36165d2843 | ||
|
|
3e9276271a | ||
|
|
af7df1448d | ||
|
|
518147c129 | ||
|
|
a0072a2cf9 | ||
|
|
c4518e964f | ||
|
|
c2eb09cd8f | ||
|
|
89b4e7ae02 | ||
|
|
714ff85806 | ||
|
|
589ddcb4fa | ||
|
|
3d09b0cb83 | ||
|
|
3012dd67ac | ||
|
|
60f826fb2d | ||
|
|
5d24062d42 | ||
|
|
d553919dfb | ||
|
|
661743c7e5 | ||
|
|
1dc22e3f0d | ||
|
|
808843457a | ||
|
|
42497c664f | ||
|
|
88cc78d5b7 | ||
|
|
9ac9a28db7 | ||
|
|
5cf0d887b1 | ||
|
|
58c2df2dec | ||
|
|
1644fdd076 | ||
|
|
cd25740b61 | ||
|
|
28045399f3 | ||
|
|
e630334837 | ||
|
|
b97df057c1 | ||
|
|
546a7386ff | ||
|
|
4b117c4736 | ||
|
|
bc968d17e3 | ||
|
|
51c2fe9742 | ||
|
|
25a38ad2b6 | ||
|
|
8046efd261 | ||
|
|
9a4acba118 | ||
|
|
d9d67e33e7 | ||
|
|
18d6a96f80 | ||
|
|
458a7c532c | ||
|
|
701c217791 | ||
|
|
e042a22d0f | ||
|
|
4fca00014c | ||
|
|
1c2eaa9d29 | ||
|
|
1f32e89d95 | ||
|
|
b7a379604c | ||
|
|
cea461e8f2 | ||
|
|
73157c7141 | ||
|
|
72dc895c52 | ||
|
|
2aca65a126 | ||
|
|
ac2e6990c3 | ||
|
|
8f0900f95e | ||
|
|
2549a8c6be | ||
|
|
88ebe1c73e | ||
|
|
08922cfe29 | ||
|
|
952a2ebbf4 | ||
|
|
075846c731 | ||
|
|
d531de6774 | ||
|
|
cedcf3ac04 | ||
|
|
8ce637a004 | ||
|
|
10250286c7 | ||
|
|
a43d43f2c4 | ||
|
|
8356979e1f | ||
|
|
46d9a8dc46 | ||
|
|
cb3854edaa | ||
|
|
083a266b0b | ||
|
|
d6fdf1c01a | ||
|
|
b679e33d47 | ||
|
|
e63b9ef825 | ||
|
|
4b5b0dfdce | ||
|
|
572260c0f0 | ||
|
|
0e5e2648b3 | ||
|
|
144471ce78 | ||
|
|
98cb7fc8cd | ||
|
|
ca8e00fc15 | ||
|
|
93b0b1b0b1 | ||
|
|
34a442bbef | ||
|
|
37918ae745 | ||
|
|
dca164e967 | ||
|
|
8ac2365406 | ||
|
|
c1a2bf14da | ||
|
|
a7af7df9cb | ||
|
|
8d148c7ee4 | ||
|
|
0b94a1405d | ||
|
|
b083187e6a | ||
|
|
4dcf81050e | ||
|
|
c97fa946d5 | ||
|
|
c35f5b0189 | ||
|
|
dd4aafe148 | ||
|
|
adb56abd99 | ||
|
|
def978b334 | ||
|
|
f7ca4fa106 | ||
|
|
ff7a7937c5 | ||
|
|
90c23026c2 | ||
|
|
e5e4f33ac7 | ||
|
|
5449dbc775 | ||
|
|
52c5a9d380 | ||
|
|
74d59f87c2 | ||
|
|
98ba8b7491 | ||
|
|
e05404f89c | ||
|
|
9e40cc177a | ||
|
|
315f7c6e7f | ||
|
|
13eedd95f9 | ||
|
|
a193129920 | ||
|
|
d2c205b082 | ||
|
|
02184dbfc5 | ||
|
|
5b1edcdd0e | ||
|
|
b4f9e9ae56 | ||
|
|
a17022f7cc | ||
|
|
615f36119e | ||
|
|
fd8c63772f | ||
|
|
07cfa207f1 | ||
|
|
d1a3758c39 | ||
|
|
7de391e0d6 | ||
|
|
c62a83c903 | ||
|
|
82a05738f0 | ||
|
|
e25651f250 | ||
|
|
75d8492c51 | ||
|
|
eba34f4071 | ||
|
|
823847d90a | ||
|
|
80dc4763bf | ||
|
|
589f274493 | ||
|
|
f63faca999 | ||
|
|
d596330a0a | ||
|
|
31a3a08f53 | ||
|
|
ffde2c452d | ||
|
|
93bfb5b6f6 | ||
|
|
28c919912a | ||
|
|
12d5ca68e9 | ||
|
|
847d415f50 | ||
|
|
31d70c4ee2 | ||
|
|
06174fb52f | ||
|
|
276270eb57 | ||
|
|
b3f5874978 | ||
|
|
4b68425d86 | ||
|
|
4d88032e11 | ||
|
|
909bc25e12 | ||
|
|
2df3a7fc08 | ||
|
|
2b0b29aec5 | ||
|
|
1dced55f60 | ||
|
|
68d6b9add6 | ||
|
|
44f5093ae3 | ||
|
|
557cd656ab | ||
|
|
650f111e63 | ||
|
|
81da8f6f99 | ||
|
|
32ed552ea6 | ||
|
|
0b12f6c73d | ||
|
|
cd3b87e483 | ||
|
|
d616c9c315 | ||
|
|
006953265f | ||
|
|
4c520697fe | ||
|
|
8f5a55f89b | ||
|
|
c15fb14ccd | ||
|
|
24711f9fae | ||
|
|
7db4996638 | ||
|
|
8efc528117 | ||
|
|
d48952451a | ||
|
|
cf6fd30c73 | ||
|
|
f206241e2a | ||
|
|
07b679955e | ||
|
|
59f8f4ae14 | ||
|
|
33d72e9ae6 | ||
|
|
e28af71b6f | ||
|
|
b738cc221c | ||
|
|
f17cec0b3f | ||
|
|
ab9d4c7e7b | ||
|
|
7bae481252 | ||
|
|
765a4888df | ||
|
|
f9822c014f | ||
|
|
1e36c1c74f | ||
|
|
c5c53011da | ||
|
|
fdfb58cc3e | ||
|
|
1079d8604c | ||
|
|
4454edc14c | ||
|
|
7d5304928b | ||
|
|
bf17177270 | ||
|
|
2320c10463 | ||
|
|
50cba50a8d | ||
|
|
2eabe24896 | ||
|
|
99b850555d | ||
|
|
69e3c01cbf | ||
|
|
77b5a4a215 | ||
|
|
214b5bcfb9 | ||
|
|
e1087cdfbc | ||
|
|
844824e8e9 | ||
|
|
8d8773fc0e | ||
|
|
bf71dce60c | ||
|
|
66e889e4c1 | ||
|
|
ee2228c5fc | ||
|
|
dd3a79bcf7 | ||
|
|
84ed659d8c | ||
|
|
fbceeb1770 | ||
|
|
a7b58257e1 | ||
|
|
b622306ff7 | ||
|
|
ee095371b8 | ||
|
|
73cb596122 | ||
|
|
d0425791ca | ||
|
|
bacb9e2249 | ||
|
|
c0c70b26d1 | ||
|
|
6837d1f196 | ||
|
|
f247955942 | ||
|
|
f7f0923375 | ||
|
|
d1556837e1 | ||
|
|
7c731f0109 | ||
|
|
ff125b8c6c | ||
|
|
9a4927607d | ||
|
|
6951623dd0 | ||
|
|
eb7602fe19 | ||
|
|
a1def720cc | ||
|
|
0866e2a54b | ||
|
|
99933bf571 | ||
|
|
b1fbf1958d | ||
|
|
e3971ffbff | ||
|
|
802d79ae32 | ||
|
|
6ae53cb732 | ||
|
|
0a8d367633 | ||
|
|
75cba52f60 | ||
|
|
5884290fff | ||
|
|
0152dbb0dc | ||
|
|
5d7269968a | ||
|
|
a0b997308a | ||
|
|
aa95c9a773 | ||
|
|
5907c9e141 | ||
|
|
266af31bcb | ||
|
|
988afcb82d | ||
|
|
ec96854186 | ||
|
|
26a6c8e47a | ||
|
|
d5666c4ff4 | ||
|
|
ec43561c2d | ||
|
|
4faf00b928 | ||
|
|
4b78440c59 | ||
|
|
aafe6b0260 | ||
|
|
74b45392fc | ||
|
|
f8ef55eeac | ||
|
|
897e7b6e61 | ||
|
|
70b1cfef4a | ||
|
|
4c9cc343cd | ||
|
|
5213426f0a | ||
|
|
5e22d9fedb | ||
|
|
a5cdc6c912 | ||
|
|
6a32d8ac42 | ||
|
|
abb9d5a5b1 | ||
|
|
e54455705d | ||
|
|
c39cf55509 | ||
|
|
1a89d09f40 | ||
|
|
4ee126c840 | ||
|
|
39cb87cf2b | ||
|
|
3c6d3845ec | ||
|
|
51e3e0ff29 | ||
|
|
5c382b3c57 | ||
|
|
065f70705d | ||
|
|
a3fba0cb07 | ||
|
|
77fa5c2921 | ||
|
|
cc84eb108d | ||
|
|
2409845437 | ||
|
|
83c7c29132 | ||
|
|
7a03fe7353 | ||
|
|
5bae01fa68 | ||
|
|
9d6bbfb38a | ||
|
|
dac97f6aeb | ||
|
|
1494cd3702 | ||
|
|
3dfc76b769 | ||
|
|
dab0f3cf22 | ||
|
|
8d5fc2f281 | ||
|
|
9b26390d92 | ||
|
|
7309a5cb06 | ||
|
|
099b6ff460 | ||
|
|
eb86d6a2d7 | ||
|
|
7d600c1c5a | ||
|
|
259624ac07 | ||
|
|
d16d1f81b0 | ||
|
|
b3ff51b9bc | ||
|
|
c9f50745ff | ||
|
|
95f0a44fc0 | ||
|
|
174b2ed62e | ||
|
|
594c48d19a | ||
|
|
096ad8c95c | ||
|
|
fd70213ca2 | ||
|
|
212ec66e91 | ||
|
|
02235007e1 | ||
|
|
6063a6bde8 | ||
|
|
6d92608877 | ||
|
|
e771902a07 | ||
|
|
2ce66c0a85 | ||
|
|
f7909fad71 | ||
|
|
5e00158b00 | ||
|
|
218880cdd9 | ||
|
|
31e5ab1e6d | ||
|
|
a9e998d27d | ||
|
|
b579bf2b03 | ||
|
|
cae8fd0013 | ||
|
|
de9f80c41b | ||
|
|
085b64cde4 | ||
|
|
0abad97de3 | ||
|
|
a2f2cc6a85 | ||
|
|
028811eb97 | ||
|
|
d67c03af12 | ||
|
|
c95a89c1f1 | ||
|
|
499246a4a4 | ||
|
|
bd3d413ffd | ||
|
|
9195f05bba | ||
|
|
63f7495e88 | ||
|
|
6994e41eb3 | ||
|
|
1d46edccb5 | ||
|
|
c771f24626 | ||
|
|
3e6b5918a2 | ||
|
|
7feb873ef6 | ||
|
|
3c72a93c21 | ||
|
|
f07cae82b0 | ||
|
|
2b48c4b08d | ||
|
|
855b2c3171 | ||
|
|
82f20da46e | ||
|
|
72c7db39f2 | ||
|
|
c852bb00f2 | ||
|
|
a5db82e3a0 | ||
|
|
0636368c8c | ||
|
|
3516bf1bb1 | ||
|
|
d5ba8533fa | ||
|
|
40db077d3d | ||
|
|
d4d95012c7 | ||
|
|
99b15004dd | ||
|
|
c777a3805d | ||
|
|
52facc13ed | ||
|
|
53e7c87604 | ||
|
|
8618613325 | ||
|
|
59b1662b92 | ||
|
|
efeb26c634 | ||
|
|
e287d68d0f | ||
|
|
3786db2dba | ||
|
|
46316198cb | ||
|
|
243394002f | ||
|
|
60f3ca6f70 | ||
|
|
5e9619d3fb | ||
|
|
b9053655db | ||
|
|
1f35b37712 | ||
|
|
d7484aacad | ||
|
|
98414e8bf6 | ||
|
|
c1f2dd3688 | ||
|
|
982b9e77d4 | ||
|
|
c75a47322b | ||
|
|
bb05d19a5a | ||
|
|
8c18970b56 | ||
|
|
2c615d78a2 | ||
|
|
45a9805656 | ||
|
|
504029281a | ||
|
|
2d699f93fc | ||
|
|
1653a70693 | ||
|
|
4667372114 | ||
|
|
6d9702561a | ||
|
|
4533e43009 | ||
|
|
c7b00733c1 | ||
|
|
b023570fae | ||
|
|
8c315ab874 | ||
|
|
014db05f9c | ||
|
|
d8f601248b | ||
|
|
9c75afca58 | ||
|
|
8f2f2c201f | ||
|
|
e66235f380 | ||
|
|
636167ac7f | ||
|
|
4eac2b10d6 | ||
|
|
d15a573544 | ||
|
|
8d22cbdcca | ||
|
|
b72db9e783 | ||
|
|
a446a4f4fe | ||
|
|
f81d766584 | ||
|
|
ef592606a0 | ||
|
|
4e322fb501 | ||
|
|
b1e48a46c7 | ||
|
|
83700461fc | ||
|
|
853181e36f | ||
|
|
e7e7648c55 | ||
|
|
20643c933e | ||
|
|
0227582684 | ||
|
|
c4db0f9a60 | ||
|
|
5479d32aa3 | ||
|
|
6aabe72fce | ||
|
|
ee110a8e02 | ||
|
|
65b6e1c2bb | ||
|
|
826da4b19e | ||
|
|
630ac1b318 | ||
|
|
23589cc2af | ||
|
|
b349351e6e | ||
|
|
7bddd14419 | ||
|
|
894e21acbf | ||
|
|
524d672307 | ||
|
|
d051588789 | ||
|
|
ea807fcdcc | ||
|
|
a7f0af939b | ||
|
|
4f926df7cf | ||
|
|
1dad3f0975 | ||
|
|
885a9db52e | ||
|
|
8d40ead9b7 | ||
|
|
86bcb47b7d | ||
|
|
f08594cc22 | ||
|
|
56b6fa90b3 | ||
|
|
292d950465 | ||
|
|
ee431f755c | ||
|
|
e00d0b98de | ||
|
|
a8b9741866 | ||
|
|
7855031ecc | ||
|
|
e12d57e6f2 | ||
|
|
0d2ae19c80 | ||
|
|
804cf6d71c | ||
|
|
e342b68f0a | ||
|
|
022805b56b | ||
|
|
eb57d4b510 | ||
|
|
a5a51ba76a | ||
|
|
32efef71f4 | ||
|
|
98c08b2b66 | ||
|
|
5ea34b2efb | ||
|
|
0f3d5c80e4 | ||
|
|
cabaccb9fd | ||
|
|
4d1fe6678f | ||
|
|
04af0e6648 | ||
|
|
7a696ef616 | ||
|
|
691c11d520 | ||
|
|
109ffdaec5 | ||
|
|
aac1b7dc24 | ||
|
|
96782d9584 | ||
|
|
b17ea88bf7 | ||
|
|
38973a80c3 | ||
|
|
4a7b22cf23 | ||
|
|
a4ee1c2e72 | ||
|
|
39fe903498 | ||
|
|
1503b4c834 |
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.github
|
||||||
|
docs
|
||||||
|
examples
|
||||||
|
functions
|
||||||
|
hack
|
||||||
|
site
|
||||||
|
travis
|
||||||
|
*.md
|
||||||
68
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
68
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ""
|
||||||
|
labels:
|
||||||
|
- kind/bug
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please read this page: https://kubernetes-sigs.github.io/kustomize/contributing/bugs/ before
|
||||||
|
filing a bug
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Feel free to skip the sections if they are not applicable. -->
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
**Files that can reproduce the issue**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We cannot figure out or fix the issue if we don't know how to reproduce. Please
|
||||||
|
provide a minimum set of files that can reproduce the issue. You can paste the
|
||||||
|
file contents here or provide a link to a tarball or git repo.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
kustomization.yaml
|
||||||
|
|
||||||
|
```
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
resources.yaml
|
||||||
|
|
||||||
|
```
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
...
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Expected output**
|
||||||
|
|
||||||
|
<!-- What's the expected output? -->
|
||||||
|
|
||||||
|
**Actual output**
|
||||||
|
|
||||||
|
<!-- What's the actual output? -->
|
||||||
|
|
||||||
|
**Kustomize version**
|
||||||
|
|
||||||
|
<!-- Please use the latest version when it's possible. -->
|
||||||
|
|
||||||
|
**Platform**
|
||||||
|
|
||||||
|
<!-- Linux/macOS/Windows? -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
|
||||||
|
<!-- Add any other context about the problem here. -->
|
||||||
1
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
26
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ""
|
||||||
|
labels:
|
||||||
|
- kind/feature
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Feel free to skip the sections if they are not applicable. -->
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
|
||||||
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
|
||||||
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
9
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: Question
|
||||||
|
about: Ask a question about the kustomize
|
||||||
|
title: "[Question]"
|
||||||
|
labels: ""
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Please describe your question here -->
|
||||||
113
.github/workflows/go.yml
vendored
Normal file
113
.github/workflows/go.yml
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
name: Go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
lint:
|
||||||
|
name: Lint
|
||||||
|
runs-on: [ubuntu-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ^1.16
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: ./hack/kyaml-pre-commit.sh
|
||||||
|
env:
|
||||||
|
KUSTOMIZE_DOCKER_E2E: false # don't need to do e2e tests for linting
|
||||||
|
|
||||||
|
test-linux:
|
||||||
|
name: Test Linux
|
||||||
|
runs-on: [ubuntu-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ^1.16
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Test kyaml
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./kyaml
|
||||||
|
|
||||||
|
- name: Test api
|
||||||
|
run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||||
|
working-directory: ./api
|
||||||
|
|
||||||
|
- name: Test cmd/config
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./cmd/config
|
||||||
|
env:
|
||||||
|
KUSTOMIZE_DOCKER_E2E: true
|
||||||
|
|
||||||
|
test-macos:
|
||||||
|
name: Test MacOS
|
||||||
|
runs-on: [macos-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ^1.16
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Test kyaml
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./kyaml
|
||||||
|
|
||||||
|
- name: Test api
|
||||||
|
run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||||
|
working-directory: ./api
|
||||||
|
|
||||||
|
- name: Test cmd/config
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./cmd/config
|
||||||
|
env:
|
||||||
|
KUSTOMIZE_DOCKER_E2E: false # docker not installed on mac
|
||||||
|
|
||||||
|
test-windows:
|
||||||
|
name: Test Windows
|
||||||
|
runs-on: [windows-latest]
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ^1.16
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Test kyaml
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./kyaml
|
||||||
|
|
||||||
|
# TODO: uncomment once Windows tests are passing.
|
||||||
|
# - name: Test api
|
||||||
|
# run: go test -cover ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
|
||||||
|
# working-directory: ./api
|
||||||
|
|
||||||
|
- name: Test cmd/config
|
||||||
|
run: go test -cover ./...
|
||||||
|
working-directory: ./cmd/config
|
||||||
|
env:
|
||||||
|
KUSTOMIZE_DOCKER_E2E: false # docker on windows not working well yet
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,3 +19,5 @@
|
|||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
*.DS_store
|
*.DS_store
|
||||||
|
|
||||||
|
.bin
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
|
[SIG-CLI]: https://github.com/kubernetes/community/tree/master/sig-cli
|
||||||
|
[Slack channel]: https://kubernetes.slack.com/messages/kustomize
|
||||||
|
[Mailing list]: https://groups.google.com/forum/#!forum/kubernetes-sig-cli
|
||||||
|
|
||||||
|
[OWNERS file spec]: https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md
|
||||||
|
[Kustomize OWNERS_ALIASES]: https://github.com/kubernetes-sigs/kustomize/blob/8049f7b1af52e8a7ec26faf6cf714f560d0043c5/OWNERS_ALIASES
|
||||||
|
[SIG-CLI Teams]: https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml
|
||||||
|
[Github permissions]: https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#repository-access-for-each-permission-level
|
||||||
|
|
||||||
|
[Contributor License Agreement]: https://git.k8s.io/community/CLA.md
|
||||||
|
[Kubernetes Contributor Guide]: http://git.k8s.io/community/contributors/guide
|
||||||
|
[Contributor Cheat Sheet]: https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md
|
||||||
|
[CNCF Code of Conduct]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md
|
||||||
|
[Kubernetes Community Membership]: https://github.com/kubernetes/community/blob/master/community-membership.md
|
||||||
|
|
||||||
|
[Contribution Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/
|
||||||
|
[MacOS Dev Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/mac/
|
||||||
|
[Windows Dev Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/windows/
|
||||||
|
|
||||||
# Contributing Guidelines
|
# Contributing Guidelines
|
||||||
|
|
||||||
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt:
|
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the [CNCF Code of Conduct]. Here is an excerpt:
|
||||||
|
|
||||||
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
|
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
|
||||||
|
|
||||||
@@ -8,19 +27,45 @@ _As contributors and maintainers of this project, and in the interest of fosteri
|
|||||||
|
|
||||||
Dev guides:
|
Dev guides:
|
||||||
|
|
||||||
- [Mac](docs/macDevGuide.md)
|
- [Contribution Guide]
|
||||||
|
- [MacOS Dev Guide]
|
||||||
|
- [Windows Dev Guide]
|
||||||
|
|
||||||
We have full documentation on how to get started contributing here:
|
General resources for contributors:
|
||||||
|
|
||||||
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
|
- [Contributor License Agreement] - Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
|
||||||
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
|
- [Kubernetes Contributor Guide] - Main contributor documentation.
|
||||||
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md) - Common resources for existing developers
|
- [Contributor Cheat Sheet] - Common resources for existing developers.
|
||||||
|
|
||||||
|
Here are some additional ideas to help you get started with Kustomize:
|
||||||
|
- Attend a Kustomize Bug Scrub. Check the [SIG-CLI] meetings list to find the next one.
|
||||||
|
- Help triage issues by confirming validity and applying the appropriate `kind` label (e.g. comment `/kind bug`).
|
||||||
|
- Pick up an issue to fix. Issues with the `help-wanted` label are a good place to start, but you can also look for any issue with the `triage/accepted` label and no assignee. Remember to `/assign` yourself to let others know you're working on it.
|
||||||
|
- Help confirm new issues labelled `kind/bug` by reproducing them with the latest release.
|
||||||
|
- Support Kustomize users by responding to questions on issues labelled `kind/support` or in the [Slack channel].
|
||||||
|
|
||||||
## Mentorship
|
## Mentorship
|
||||||
|
|
||||||
- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
|
- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
|
||||||
|
|
||||||
|
## Contributor Ladder
|
||||||
|
|
||||||
|
Kustomize follows the [Kubernetes Community Membership] contributor ladder. Roles are as follows:
|
||||||
|
|
||||||
|
1. Contributor: Anyone who actively contributes code, issues or reviews to the project. All contributors must sign the [Contributor License Agreement].
|
||||||
|
1. Reviewer: Contributors with a history of review and authorship on Kustomize. Has LGTM rights on the Kustomize repo (as do all kubernetes-sigs org members). Active contributors are encouraged to join the reviewers list to be automatically pinged on PRs.
|
||||||
|
1. Approver: Highly experienced active reviewer and contributor to Kustomize. Has both LTGM and approval rights on the Kustomize repo, as well as "maintain" [Github permissions].
|
||||||
|
1. Owner: Approver who sets technical direction and makes or approves design decisions for the project. Has LGTM and approval rights on the Kustomize repo as well as "admin" [Github permissions].
|
||||||
|
|
||||||
|
The kyaml module within the Kustomize repo has additional owners following the same ladder.
|
||||||
|
|
||||||
|
Administrative notes:
|
||||||
|
|
||||||
|
- The [OWNERS file spec] is a useful resources in making changes.
|
||||||
|
- Maintainers and admins must be added to the appropriate lists in both [Kustomize OWNERS_ALIASES] and [SIG-CLI Teams]. If this isn't done, the individual in question will lack either PR approval rights (Kustomize list) or the appropriate Github repository permissions (community list).
|
||||||
|
|
||||||
|
|
||||||
## Contact Information
|
## Contact Information
|
||||||
|
|
||||||
- [Slack channel](https://kubernetes.slack.com/messages/sig-cli)
|
- [Slack channel]
|
||||||
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-cli)
|
- [Mailing list]
|
||||||
|
|||||||
241
Makefile
241
Makefile
@@ -3,77 +3,93 @@
|
|||||||
#
|
#
|
||||||
# Makefile for kustomize CLI and API.
|
# Makefile for kustomize CLI and API.
|
||||||
|
|
||||||
MYGOBIN := $(shell go env GOPATH)/bin
|
SHELL := /usr/bin/env bash
|
||||||
SHELL := /bin/bash
|
GOOS = $(shell go env GOOS)
|
||||||
|
GOARCH = $(shell go env GOARCH)
|
||||||
|
MYGOBIN = $(shell go env GOBIN)
|
||||||
|
ifeq ($(MYGOBIN),)
|
||||||
|
MYGOBIN = $(shell go env GOPATH)/bin
|
||||||
|
endif
|
||||||
export PATH := $(MYGOBIN):$(PATH)
|
export PATH := $(MYGOBIN):$(PATH)
|
||||||
|
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
|
||||||
|
LATEST_V4_RELEASE=v4.4.0
|
||||||
|
|
||||||
|
# Provide defaults for REPO_OWNER and REPO_NAME if not present.
|
||||||
|
# Typically these values would be provided by Prow.
|
||||||
|
ifndef REPO_OWNER
|
||||||
|
REPO_OWNER := "kubernetes-sigs"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef REPO_NAME
|
||||||
|
REPO_NAME := "kustomize"
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: verify-kustomize
|
all: install-tools verify-kustomize
|
||||||
|
|
||||||
.PHONY: verify-kustomize
|
.PHONY: verify-kustomize
|
||||||
verify-kustomize: \
|
verify-kustomize: \
|
||||||
lint-kustomize \
|
lint-kustomize \
|
||||||
test-unit-kustomize-all \
|
test-unit-kustomize-all \
|
||||||
test-examples-kustomize-against-HEAD \
|
test-examples-kustomize-against-HEAD \
|
||||||
test-examples-kustomize-against-latest
|
test-examples-kustomize-against-v4-release
|
||||||
|
|
||||||
# The following target referenced by a file in
|
# The following target referenced by a file in
|
||||||
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
|
||||||
.PHONY: prow-presubmit-check
|
.PHONY: prow-presubmit-check
|
||||||
prow-presubmit-check: \
|
prow-presubmit-check: \
|
||||||
|
install-tools \
|
||||||
lint-kustomize \
|
lint-kustomize \
|
||||||
|
test-multi-module \
|
||||||
test-unit-kustomize-all \
|
test-unit-kustomize-all \
|
||||||
test-unit-cmd-all \
|
test-unit-cmd-all \
|
||||||
test-go-mod
|
test-go-mod \
|
||||||
|
test-examples-kustomize-against-HEAD \
|
||||||
|
test-examples-kustomize-against-v4-release
|
||||||
|
|
||||||
.PHONY: verify-kustomize-e2e
|
.PHONY: verify-kustomize-e2e
|
||||||
verify-kustomize-e2e: test-examples-e2e-kustomize
|
verify-kustomize-e2e: test-examples-e2e-kustomize
|
||||||
|
|
||||||
# Other builds in this repo might want a different linter version.
|
# Other builds in this repo might want a different linter version.
|
||||||
# Without one Makefile to rule them all, the different makes
|
# Without one Makefile to rule them all, the different makes
|
||||||
# cannot assume that golanci-lint is at the version they want
|
# cannot assume that golanci-lint is at the version they want.
|
||||||
# since everything uses the same implicit GOPATH.
|
# This installs what kustomize wants to use.
|
||||||
# This installs in a temp dir to avoid overwriting someone else's
|
|
||||||
# linter, then installs in MYGOBIN with a new name.
|
|
||||||
# Version pinned by hack/go.mod
|
|
||||||
$(MYGOBIN)/golangci-lint-kustomize:
|
$(MYGOBIN)/golangci-lint-kustomize:
|
||||||
( \
|
rm -f $(CURDIR)/hack/golangci-lint
|
||||||
set -e; \
|
GOBIN=$(CURDIR)/hack go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.23.8
|
||||||
export GOBIN=$$(mktemp -d); \
|
mv $(CURDIR)/hack/golangci-lint $(MYGOBIN)/golangci-lint-kustomize
|
||||||
cd hack; \
|
|
||||||
GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint; \
|
|
||||||
mv $$GOBIN/golangci-lint $(MYGOBIN)/golangci-lint-kustomize \
|
|
||||||
)
|
|
||||||
|
|
||||||
# Version pinned by api/go.mod
|
|
||||||
$(MYGOBIN)/mdrip:
|
$(MYGOBIN)/mdrip:
|
||||||
cd api; \
|
go install github.com/monopole/mdrip@v1.0.2
|
||||||
go install github.com/monopole/mdrip
|
|
||||||
|
|
||||||
# Version pinned by api/go.mod
|
|
||||||
$(MYGOBIN)/stringer:
|
$(MYGOBIN)/stringer:
|
||||||
cd api; \
|
go get golang.org/x/tools/cmd/stringer
|
||||||
go install golang.org/x/tools/cmd/stringer
|
|
||||||
|
|
||||||
# Version pinned by api/go.mod
|
|
||||||
$(MYGOBIN)/goimports:
|
$(MYGOBIN)/goimports:
|
||||||
cd api; \
|
go get golang.org/x/tools/cmd/goimports
|
||||||
go install golang.org/x/tools/cmd/goimports
|
|
||||||
|
|
||||||
# Install resource from whatever is checked out.
|
# Build from local source.
|
||||||
$(MYGOBIN)/resource:
|
$(MYGOBIN)/gorepomod:
|
||||||
cd cmd/resource; \
|
cd cmd/gorepomod; \
|
||||||
go install .
|
go install .
|
||||||
|
|
||||||
# To pin pluginator, use this recipe instead:
|
# Build from local source.
|
||||||
# cd api;
|
$(MYGOBIN)/k8scopy:
|
||||||
# go install sigs.k8s.io/kustomize/pluginator/v2
|
cd cmd/k8scopy; \
|
||||||
|
go install .
|
||||||
|
|
||||||
|
# Build from local source.
|
||||||
$(MYGOBIN)/pluginator:
|
$(MYGOBIN)/pluginator:
|
||||||
cd pluginator; \
|
cd cmd/pluginator; \
|
||||||
go install .
|
go install .
|
||||||
|
|
||||||
# Install kustomize from whatever is checked out.
|
# Build from local source.
|
||||||
$(MYGOBIN)/kustomize:
|
$(MYGOBIN)/prchecker:
|
||||||
|
cd cmd/prchecker; \
|
||||||
|
go install .
|
||||||
|
|
||||||
|
# Build from local source.
|
||||||
|
$(MYGOBIN)/kustomize: build-kustomize-api
|
||||||
cd kustomize; \
|
cd kustomize; \
|
||||||
go install .
|
go install .
|
||||||
|
|
||||||
@@ -81,8 +97,12 @@ $(MYGOBIN)/kustomize:
|
|||||||
install-tools: \
|
install-tools: \
|
||||||
$(MYGOBIN)/goimports \
|
$(MYGOBIN)/goimports \
|
||||||
$(MYGOBIN)/golangci-lint-kustomize \
|
$(MYGOBIN)/golangci-lint-kustomize \
|
||||||
|
$(MYGOBIN)/gorepomod \
|
||||||
|
$(MYGOBIN)/helmV3 \
|
||||||
|
$(MYGOBIN)/k8scopy \
|
||||||
$(MYGOBIN)/mdrip \
|
$(MYGOBIN)/mdrip \
|
||||||
$(MYGOBIN)/pluginator \
|
$(MYGOBIN)/pluginator \
|
||||||
|
$(MYGOBIN)/prchecker \
|
||||||
$(MYGOBIN)/stringer
|
$(MYGOBIN)/stringer
|
||||||
|
|
||||||
### Begin kustomize plugin rules.
|
### Begin kustomize plugin rules.
|
||||||
@@ -114,9 +134,9 @@ pSrc=plugin/builtin
|
|||||||
_builtinplugins = \
|
_builtinplugins = \
|
||||||
AnnotationsTransformer.go \
|
AnnotationsTransformer.go \
|
||||||
ConfigMapGenerator.go \
|
ConfigMapGenerator.go \
|
||||||
|
IAMPolicyGenerator.go \
|
||||||
HashTransformer.go \
|
HashTransformer.go \
|
||||||
ImageTagTransformer.go \
|
ImageTagTransformer.go \
|
||||||
InventoryTransformer.go \
|
|
||||||
LabelTransformer.go \
|
LabelTransformer.go \
|
||||||
LegacyOrderTransformer.go \
|
LegacyOrderTransformer.go \
|
||||||
NamespaceTransformer.go \
|
NamespaceTransformer.go \
|
||||||
@@ -124,8 +144,11 @@ _builtinplugins = \
|
|||||||
PatchStrategicMergeTransformer.go \
|
PatchStrategicMergeTransformer.go \
|
||||||
PatchTransformer.go \
|
PatchTransformer.go \
|
||||||
PrefixSuffixTransformer.go \
|
PrefixSuffixTransformer.go \
|
||||||
|
ReplacementTransformer.go \
|
||||||
ReplicaCountTransformer.go \
|
ReplicaCountTransformer.go \
|
||||||
SecretGenerator.go
|
SecretGenerator.go \
|
||||||
|
ValueAddTransformer.go \
|
||||||
|
HelmChartInflationGenerator.go
|
||||||
|
|
||||||
# Maintaining this explicit list of generated files, and
|
# Maintaining this explicit list of generated files, and
|
||||||
# adding it as a dependency to a few targets, to assure
|
# adding it as a dependency to a few targets, to assure
|
||||||
@@ -139,9 +162,9 @@ builtinplugins = $(patsubst %,$(pGen)/%,$(_builtinplugins))
|
|||||||
# that file, will be recreated.
|
# that file, will be recreated.
|
||||||
$(pGen)/AnnotationsTransformer.go: $(pSrc)/annotationstransformer/AnnotationsTransformer.go
|
$(pGen)/AnnotationsTransformer.go: $(pSrc)/annotationstransformer/AnnotationsTransformer.go
|
||||||
$(pGen)/ConfigMapGenerator.go: $(pSrc)/configmapgenerator/ConfigMapGenerator.go
|
$(pGen)/ConfigMapGenerator.go: $(pSrc)/configmapgenerator/ConfigMapGenerator.go
|
||||||
|
$(pGen)/GkeSaGenerator.go: $(pSrc)/gkesagenerator/GkeSaGenerator.go
|
||||||
$(pGen)/HashTransformer.go: $(pSrc)/hashtransformer/HashTransformer.go
|
$(pGen)/HashTransformer.go: $(pSrc)/hashtransformer/HashTransformer.go
|
||||||
$(pGen)/ImageTagTransformer.go: $(pSrc)/imagetagtransformer/ImageTagTransformer.go
|
$(pGen)/ImageTagTransformer.go: $(pSrc)/imagetagtransformer/ImageTagTransformer.go
|
||||||
$(pGen)/InventoryTransformer.go: $(pSrc)/inventorytransformer/InventoryTransformer.go
|
|
||||||
$(pGen)/LabelTransformer.go: $(pSrc)/labeltransformer/LabelTransformer.go
|
$(pGen)/LabelTransformer.go: $(pSrc)/labeltransformer/LabelTransformer.go
|
||||||
$(pGen)/LegacyOrderTransformer.go: $(pSrc)/legacyordertransformer/LegacyOrderTransformer.go
|
$(pGen)/LegacyOrderTransformer.go: $(pSrc)/legacyordertransformer/LegacyOrderTransformer.go
|
||||||
$(pGen)/NamespaceTransformer.go: $(pSrc)/namespacetransformer/NamespaceTransformer.go
|
$(pGen)/NamespaceTransformer.go: $(pSrc)/namespacetransformer/NamespaceTransformer.go
|
||||||
@@ -149,8 +172,11 @@ $(pGen)/PatchJson6902Transformer.go: $(pSrc)/patchjson6902transformer/PatchJson6
|
|||||||
$(pGen)/PatchStrategicMergeTransformer.go: $(pSrc)/patchstrategicmergetransformer/PatchStrategicMergeTransformer.go
|
$(pGen)/PatchStrategicMergeTransformer.go: $(pSrc)/patchstrategicmergetransformer/PatchStrategicMergeTransformer.go
|
||||||
$(pGen)/PatchTransformer.go: $(pSrc)/patchtransformer/PatchTransformer.go
|
$(pGen)/PatchTransformer.go: $(pSrc)/patchtransformer/PatchTransformer.go
|
||||||
$(pGen)/PrefixSuffixTransformer.go: $(pSrc)/prefixsuffixtransformer/PrefixSuffixTransformer.go
|
$(pGen)/PrefixSuffixTransformer.go: $(pSrc)/prefixsuffixtransformer/PrefixSuffixTransformer.go
|
||||||
|
$(pGen)/ReplacementTransformer.go: $(pSrc)/replacementtransformer/ReplacementTransformer.go
|
||||||
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
$(pGen)/ReplicaCountTransformer.go: $(pSrc)/replicacounttransformer/ReplicaCountTransformer.go
|
||||||
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
$(pGen)/SecretGenerator.go: $(pSrc)/secretgenerator/SecretGenerator.go
|
||||||
|
$(pGen)/ValueAddTransformer.go: $(pSrc)/valueaddtransformer/ValueAddTransformer.go
|
||||||
|
$(pGen)/HelmChartInflationGenerator.go: $(pSrc)/helmchartinflationgenerator/HelmChartInflationGenerator.go
|
||||||
|
|
||||||
# The (verbose but portable) Makefile way to convert to lowercase.
|
# The (verbose but portable) Makefile way to convert to lowercase.
|
||||||
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
toLowerCase = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
|
||||||
@@ -169,28 +195,42 @@ $(pGen)/%.go: $(MYGOBIN)/pluginator
|
|||||||
.PHONY: generate-kustomize-builtin-plugins
|
.PHONY: generate-kustomize-builtin-plugins
|
||||||
generate-kustomize-builtin-plugins: $(builtinplugins)
|
generate-kustomize-builtin-plugins: $(builtinplugins)
|
||||||
|
|
||||||
.PHONY: kustomize-external-go-plugin-build
|
.PHONY: build-kustomize-external-go-plugin
|
||||||
kustomize-external-go-plugin-build:
|
build-kustomize-external-go-plugin:
|
||||||
./hack/buildExternalGoPlugins.sh ./plugin
|
./hack/buildExternalGoPlugins.sh ./plugin
|
||||||
|
|
||||||
.PHONY: kustomize-external-go-plugin-clean
|
.PHONY: clean-kustomize-external-go-plugin
|
||||||
kustomize-external-go-plugin-clean:
|
clean-kustomize-external-go-plugin:
|
||||||
./hack/buildExternalGoPlugins.sh ./plugin clean
|
./hack/buildExternalGoPlugins.sh ./plugin clean
|
||||||
|
|
||||||
### End kustomize plugin rules.
|
### End kustomize plugin rules.
|
||||||
|
|
||||||
.PHONY: lint-kustomize
|
.PHONY: lint-kustomize
|
||||||
lint-kustomize: install-tools $(builtinplugins)
|
lint-kustomize: $(MYGOBIN)/golangci-lint-kustomize $(builtinplugins)
|
||||||
cd api; \
|
cd api; $(MYGOBIN)/golangci-lint-kustomize \
|
||||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
-c ../.golangci-kustomize.yml \
|
||||||
cd kustomize; \
|
run ./...
|
||||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
cd kustomize; $(MYGOBIN)/golangci-lint-kustomize \
|
||||||
cd pluginator; \
|
-c ../.golangci-kustomize.yml \
|
||||||
$(MYGOBIN)/golangci-lint-kustomize -c ../.golangci-kustomize.yml run ./...
|
run ./...
|
||||||
|
cd cmd/pluginator; $(MYGOBIN)/golangci-lint-kustomize \
|
||||||
|
-c ../../.golangci-kustomize.yml \
|
||||||
|
run ./...
|
||||||
|
|
||||||
|
# Used to add non-default compilation flags when experimenting with
|
||||||
|
# plugin-to-api compatibility checks.
|
||||||
|
.PHONY: build-kustomize-api
|
||||||
|
build-kustomize-api: $(builtinplugins)
|
||||||
|
cd api; go build ./...
|
||||||
|
|
||||||
|
.PHONY: generate-kustomize-api
|
||||||
|
generate-kustomize-api: $(MYGOBIN)/k8scopy
|
||||||
|
cd api; go generate ./...
|
||||||
|
|
||||||
.PHONY: test-unit-kustomize-api
|
.PHONY: test-unit-kustomize-api
|
||||||
test-unit-kustomize-api: $(builtinplugins)
|
test-unit-kustomize-api: build-kustomize-api
|
||||||
cd api; go test ./...
|
cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"; \
|
||||||
|
cd krusty; OPENAPI_TEST=true go test -run TestCustomOpenAPIFieldFromComponentWithOverlays
|
||||||
|
|
||||||
.PHONY: test-unit-kustomize-plugins
|
.PHONY: test-unit-kustomize-plugins
|
||||||
test-unit-kustomize-plugins:
|
test-unit-kustomize-plugins:
|
||||||
@@ -207,14 +247,23 @@ test-unit-kustomize-all: \
|
|||||||
test-unit-kustomize-plugins
|
test-unit-kustomize-plugins
|
||||||
|
|
||||||
test-unit-cmd-all:
|
test-unit-cmd-all:
|
||||||
./travis/kyaml-pre-commit.sh
|
./hack/kyaml-pre-commit.sh
|
||||||
|
|
||||||
test-go-mod:
|
test-go-mod:
|
||||||
./travis/check-go-mod.sh
|
./hack/check-go-mod.sh
|
||||||
|
|
||||||
.PHONY:
|
# Environment variables are defined at
|
||||||
test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
# https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md#job-environment-variables
|
||||||
./hack/testExamplesAgainstKustomize.sh HEAD
|
.PHONY: test-multi-module
|
||||||
|
test-multi-module: $(MYGOBIN)/prchecker
|
||||||
|
( \
|
||||||
|
export MYGOBIN=$(MYGOBIN); \
|
||||||
|
export REPO_OWNER=$(REPO_OWNER); \
|
||||||
|
export REPO_NAME=$(REPO_NAME); \
|
||||||
|
export PULL_NUMBER=$(PULL_NUMBER); \
|
||||||
|
export MODULES=$(MODULES); \
|
||||||
|
./hack/check-multi-module.sh; \
|
||||||
|
)
|
||||||
|
|
||||||
.PHONY:
|
.PHONY:
|
||||||
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
||||||
@@ -227,16 +276,12 @@ test-examples-e2e-kustomize: $(MYGOBIN)/mdrip $(MYGOBIN)/kind
|
|||||||
)
|
)
|
||||||
|
|
||||||
.PHONY:
|
.PHONY:
|
||||||
test-examples-kustomize-against-latest: $(MYGOBIN)/mdrip
|
test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
|
||||||
( \
|
./hack/testExamplesAgainstKustomize.sh HEAD
|
||||||
set -e; \
|
|
||||||
/bin/rm -f $(MYGOBIN)/kustomize; \
|
.PHONY:
|
||||||
echo "Installing kustomize from latest."; \
|
test-examples-kustomize-against-v4-release: $(MYGOBIN)/mdrip
|
||||||
GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v3; \
|
./hack/testExamplesAgainstKustomize.sh v4@$(LATEST_V4_RELEASE)
|
||||||
./hack/testExamplesAgainstKustomize.sh latest; \
|
|
||||||
echo "Reinstalling kustomize from HEAD."; \
|
|
||||||
cd kustomize; go install .; \
|
|
||||||
)
|
|
||||||
|
|
||||||
# linux only.
|
# linux only.
|
||||||
# This is for testing an example plugin that
|
# This is for testing an example plugin that
|
||||||
@@ -248,25 +293,38 @@ $(MYGOBIN)/kubeval:
|
|||||||
( \
|
( \
|
||||||
set -e; \
|
set -e; \
|
||||||
d=$(shell mktemp -d); cd $$d; \
|
d=$(shell mktemp -d); cd $$d; \
|
||||||
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz; \
|
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||||
tar xf kubeval-linux-amd64.tar.gz; \
|
tar xf kubeval-$(GOOS)-$(GOARCH).tar.gz; \
|
||||||
mv kubeval $(MYGOBIN); \
|
mv kubeval $(MYGOBIN); \
|
||||||
rm -rf $$d; \
|
rm -rf $$d; \
|
||||||
)
|
)
|
||||||
|
|
||||||
# linux only.
|
# linux only.
|
||||||
# This is for testing an example plugin that
|
# This is for testing an example plugin that uses helm to inflate a chart
|
||||||
# uses helm to inflate a chart for subsequent kustomization.
|
# for subsequent kustomization.
|
||||||
# Don't want to add a hard dependence in go.mod file
|
# Don't want to add a hard dependence in go.mod file to helm.
|
||||||
# to helm.
|
# Instead, download the binaries.
|
||||||
# Instead, download the binary.
|
$(MYGOBIN)/helmV2:
|
||||||
$(MYGOBIN)/helm:
|
|
||||||
( \
|
( \
|
||||||
set -e; \
|
set -e; \
|
||||||
d=$(shell mktemp -d); cd $$d; \
|
d=$(shell mktemp -d); cd $$d; \
|
||||||
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz; \
|
tgzFile=helm-v2.13.1-$(GOOS)-$(GOARCH).tar.gz; \
|
||||||
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz; \
|
wget https://storage.googleapis.com/kubernetes-helm/$$tgzFile; \
|
||||||
mv linux-amd64/helm $(MYGOBIN); \
|
tar -xvzf $$tgzFile; \
|
||||||
|
mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV2; \
|
||||||
|
rm -rf $$d \
|
||||||
|
)
|
||||||
|
|
||||||
|
# Helm V3 differs from helm V2; downloading it to provide coverage for the
|
||||||
|
# chart inflator plugin under helm v3.
|
||||||
|
$(MYGOBIN)/helmV3:
|
||||||
|
( \
|
||||||
|
set -e; \
|
||||||
|
d=$(shell mktemp -d); cd $$d; \
|
||||||
|
tgzFile=helm-v3.6.3-$(GOOS)-$(GOARCH).tar.gz; \
|
||||||
|
wget https://get.helm.sh/$$tgzFile; \
|
||||||
|
tar -xvzf $$tgzFile; \
|
||||||
|
mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV3; \
|
||||||
rm -rf $$d \
|
rm -rf $$d \
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -274,20 +332,39 @@ $(MYGOBIN)/kind:
|
|||||||
( \
|
( \
|
||||||
set -e; \
|
set -e; \
|
||||||
d=$(shell mktemp -d); cd $$d; \
|
d=$(shell mktemp -d); cd $$d; \
|
||||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
|
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(GOOS)-$(GOARCH); \
|
||||||
chmod +x ./kind; \
|
chmod +x ./kind; \
|
||||||
mv ./kind $(MYGOBIN); \
|
mv ./kind $(MYGOBIN); \
|
||||||
rm -rf $$d; \
|
rm -rf $$d; \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# linux only.
|
||||||
|
$(MYGOBIN)/gh:
|
||||||
|
( \
|
||||||
|
set -e; \
|
||||||
|
d=$(shell mktemp -d); cd $$d; \
|
||||||
|
tgzFile=gh_1.0.0_$(GOOS)_$(GOARCH).tar.gz; \
|
||||||
|
wget https://github.com/cli/cli/releases/download/v1.0.0/$$tgzFile; \
|
||||||
|
tar -xvzf $$tgzFile; \
|
||||||
|
mv gh_1.0.0_$(GOOS)_$(GOARCH)/bin/gh $(MYGOBIN)/gh; \
|
||||||
|
rm -rf $$d \
|
||||||
|
)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: kustomize-external-go-plugin-clean
|
clean: clean-kustomize-external-go-plugin
|
||||||
go clean --cache
|
go clean --cache
|
||||||
rm -f $(builtinplugins)
|
rm -f $(builtinplugins)
|
||||||
rm -f $(MYGOBIN)/pluginator
|
rm -f $(MYGOBIN)/goimports
|
||||||
rm -f $(MYGOBIN)/kustomize
|
|
||||||
rm -f $(MYGOBIN)/golangci-lint-kustomize
|
rm -f $(MYGOBIN)/golangci-lint-kustomize
|
||||||
|
rm -f $(MYGOBIN)/kustomize
|
||||||
|
rm -f $(MYGOBIN)/mdrip
|
||||||
|
rm -f $(MYGOBIN)/prchecker
|
||||||
|
rm -f $(MYGOBIN)/stringer
|
||||||
|
|
||||||
|
# Handle pluginator manually.
|
||||||
|
# rm -f $(MYGOBIN)/pluginator
|
||||||
|
|
||||||
|
# Nuke the site from orbit. It's the only way to be sure.
|
||||||
.PHONY: nuke
|
.PHONY: nuke
|
||||||
nuke: clean
|
nuke: clean
|
||||||
sudo rm -rf $(shell go env GOPATH)/pkg/mod/sigs.k8s.io
|
go clean --modcache
|
||||||
|
|||||||
6
OWNERS
6
OWNERS
@@ -1,4 +1,6 @@
|
|||||||
# See https://github.com/kubernetes/community/blob/master/community-membership.md
|
# See https://github.com/kubernetes/community/blob/master/community-membership.md
|
||||||
approvers:
|
approvers:
|
||||||
- kustomize-admins
|
- kustomize-approvers
|
||||||
- kustomize-maintainers
|
|
||||||
|
reviewers:
|
||||||
|
- kustomize-reviewers
|
||||||
|
|||||||
@@ -1,11 +1,30 @@
|
|||||||
|
# Keep *-owners and *-approvers lists in sync with *-admins and *-maintainers in
|
||||||
|
# https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml
|
||||||
aliases:
|
aliases:
|
||||||
kustomize-admins:
|
kustomize-owners:
|
||||||
|
- knverey
|
||||||
- monopole
|
- monopole
|
||||||
- pwittrock
|
- pwittrock
|
||||||
kustomize-maintainers:
|
kustomize-approvers:
|
||||||
- droot
|
|
||||||
- justinsb
|
- justinsb
|
||||||
- liujingfang1
|
- knverey
|
||||||
- mengqiy
|
|
||||||
- monopole
|
- monopole
|
||||||
|
- natasha41575
|
||||||
- pwittrock
|
- pwittrock
|
||||||
|
kustomize-reviewers:
|
||||||
|
- knverey
|
||||||
|
- monopole
|
||||||
|
- natasha41575
|
||||||
|
|
||||||
|
kyaml-approvers:
|
||||||
|
- mengqiy
|
||||||
|
- mortent
|
||||||
|
- phanimarupaka
|
||||||
|
kyaml-reviewers:
|
||||||
|
- mengqiy
|
||||||
|
- mortent
|
||||||
|
- phanimarupaka
|
||||||
|
|
||||||
|
emeritus-approvers:
|
||||||
|
- liujingfang1
|
||||||
|
- Shell32-Natsu
|
||||||
|
|||||||
97
README.md
97
README.md
@@ -9,30 +9,38 @@ patch [kubernetes style] API objects. It's like
|
|||||||
[`make`], in that what it does is declared in a file,
|
[`make`], in that what it does is declared in a file,
|
||||||
and it's like [`sed`], in that it emits edited text.
|
and it's like [`sed`], in that it emits edited text.
|
||||||
|
|
||||||
This tool is sponsored by [sig-cli] ([KEP]), and
|
This tool is sponsored by [sig-cli] ([KEP]).
|
||||||
inspired by [DAM].
|
|
||||||
|
|
||||||
|
- [Installation instructions](https://kubernetes-sigs.github.io/kustomize/installation)
|
||||||
|
- [General documentation](https://kubernetes-sigs.github.io/kustomize)
|
||||||
|
- [Examples](examples)
|
||||||
|
|
||||||
[](https://travis-ci.org/kubernetes-sigs/kustomize)
|
[](https://prow.k8s.io/job-history/kubernetes-jenkins/pr-logs/directory/kustomize-presubmit-master)
|
||||||
[](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
|
[](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
|
||||||
|
|
||||||
Download a binary from the [release page], or see
|
|
||||||
these [instructions](docs/INSTALL.md).
|
|
||||||
|
|
||||||
Browse the [docs](docs) or jump right into the
|
|
||||||
tested [examples](examples).
|
|
||||||
|
|
||||||
## kubectl integration
|
## kubectl integration
|
||||||
|
|
||||||
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
|
The kustomize build flow at [v2.0.3] was added
|
||||||
|
to [kubectl v1.14][kubectl announcement]. The kustomize
|
||||||
|
flow in kubectl remained frozen at v2.0.3 until kubectl v1.21,
|
||||||
|
which [updated it to v4.0.5][kust-in-kubectl update]. It will
|
||||||
|
be updated on a regular basis going forward, and such updates
|
||||||
|
will be reflected in the Kubernetes release notes.
|
||||||
|
|
||||||
| kubectl version | kustomize version |
|
| Kubectl version | Kustomize version |
|
||||||
|---------|--------|
|
| --- | --- |
|
||||||
| v1.16.0 | [v2.0.3](/../../tree/v2.0.3) |
|
| < v1.14 | n/a |
|
||||||
| v1.15.x | [v2.0.3](/../../tree/v2.0.3) |
|
| v1.14-v1.20 | v2.0.3 |
|
||||||
| v1.14.x | [v2.0.3](/../../tree/v2.0.3) |
|
| v1.21 | v4.0.5 |
|
||||||
|
| v1.22 | v4.2.0 |
|
||||||
|
|
||||||
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
|
[v2.0.3]: /../../tree/v2.0.3
|
||||||
|
[#2506]: https://github.com/kubernetes-sigs/kustomize/issues/2506
|
||||||
|
[#1500]: https://github.com/kubernetes-sigs/kustomize/issues/1500
|
||||||
|
[kust-in-kubectl update]: https://github.com/kubernetes/kubernetes/blob/4d75a6238a6e330337526e0513e67d02b1940b63/CHANGELOG/CHANGELOG-1.21.md#kustomize-updates-in-kubectl
|
||||||
|
|
||||||
|
For examples and guides for using the kubectl integration please
|
||||||
|
see the [kubectl book] or the [kubernetes documentation].
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -133,20 +141,8 @@ The YAML can be directly [applied] to a cluster:
|
|||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
To file bugs please read [this](docs/bugs.md).
|
- [file a bug](https://kubernetes-sigs.github.io/kustomize/contributing/bugs/) instructions
|
||||||
|
- [contribute a feature](https://kubernetes-sigs.github.io/kustomize/contributing/features/) instructions
|
||||||
Before working on an implementation, please
|
|
||||||
|
|
||||||
* Read the [eschewed feature list].
|
|
||||||
* File an issue describing
|
|
||||||
how the new feature would behave
|
|
||||||
and label it [kind/feature].
|
|
||||||
|
|
||||||
### Other communication channels
|
|
||||||
|
|
||||||
- [Slack]
|
|
||||||
- [Mailing List]
|
|
||||||
- General kubernetes [community page]
|
|
||||||
|
|
||||||
### Code of conduct
|
### Code of conduct
|
||||||
|
|
||||||
@@ -155,32 +151,27 @@ is governed by the [Kubernetes Code of Conduct].
|
|||||||
|
|
||||||
[`make`]: https://www.gnu.org/software/make
|
[`make`]: https://www.gnu.org/software/make
|
||||||
[`sed`]: https://www.gnu.org/software/sed
|
[`sed`]: https://www.gnu.org/software/sed
|
||||||
[DAM]: docs/glossary.md#declarative-application-management
|
[DAM]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#declarative-application-management
|
||||||
[KEP]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-cli/0008-kustomize.md
|
[KEP]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-cli/2377-Kustomize/README.md
|
||||||
[Kubernetes Code of Conduct]: code-of-conduct.md
|
[Kubernetes Code of Conduct]: code-of-conduct.md
|
||||||
[Mailing List]: https://groups.google.com/forum/#!forum/kubernetes-sig-cli
|
[applied]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#apply
|
||||||
[Slack]: https://kubernetes.slack.com/messages/sig-cli
|
[base]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#base
|
||||||
[applied]: docs/glossary.md#apply
|
[declarative configuration]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#declarative-application-management
|
||||||
[base]: docs/glossary.md#base
|
|
||||||
[community page]: http://kubernetes.io/community/
|
|
||||||
[declarative configuration]: docs/glossary.md#declarative-application-management
|
|
||||||
[eschewed feature list]: docs/eschewedFeatures.md
|
|
||||||
[imageBase]: docs/images/base.jpg
|
[imageBase]: docs/images/base.jpg
|
||||||
[imageOverlay]: docs/images/overlay.jpg
|
[imageOverlay]: docs/images/overlay.jpg
|
||||||
[kind/feature]: /../../labels/kind%2Ffeature
|
|
||||||
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
||||||
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
|
[kubectl book]: https://kubectl.docs.kubernetes.io/guides/introduction/kustomize/
|
||||||
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
||||||
[kubernetes style]: docs/glossary.md#kubernetes-style-object
|
[kubernetes style]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kubernetes-style-object
|
||||||
[kustomization]: docs/glossary.md#kustomization
|
[kustomization]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kustomization
|
||||||
[overlay]: docs/glossary.md#overlay
|
[overlay]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#overlay
|
||||||
[overlays]: docs/glossary.md#overlay
|
[overlays]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#overlay
|
||||||
[release page]: /../../releases
|
[release page]: https://github.com/kubernetes-sigs/kustomize/releases
|
||||||
[resource]: docs/glossary.md#resource
|
[resource]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#resource
|
||||||
[resources]: docs/glossary.md#resource
|
[resources]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#resource
|
||||||
[sig-cli]: https://github.com/kubernetes/community/blob/master/sig-cli/README.md
|
[sig-cli]: https://github.com/kubernetes/community/blob/master/sig-cli/README.md
|
||||||
[variant]: docs/glossary.md#variant
|
[variant]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#variant
|
||||||
[variants]: docs/glossary.md#variant
|
[variants]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#variant
|
||||||
[v2.0.3]: /../../releases/tag/v2.0.3
|
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
|
||||||
[v2.1.0]: /../../releases/tag/v2.1.0
|
[v2.1.0]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.1.0
|
||||||
[workflows]: docs/workflows.md
|
[workflows]: https://kubernetes-sigs.github.io/kustomize/guides
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ package builtins
|
|||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/api/filters/annotations"
|
"sigs.k8s.io/kustomize/api/filters/annotations"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,10 +14,6 @@ import (
|
|||||||
type AnnotationsTransformerPlugin struct {
|
type AnnotationsTransformerPlugin struct {
|
||||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
|
|
||||||
// YAMLSupport can be set to true to use the kyaml filter instead of the
|
|
||||||
// kunstruct transformer
|
|
||||||
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AnnotationsTransformerPlugin) Config(
|
func (p *AnnotationsTransformerPlugin) Config(
|
||||||
@@ -30,27 +24,13 @@ func (p *AnnotationsTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
if p.YAMLSupport {
|
if len(p.Annotations) == 0 {
|
||||||
for _, r := range m.Resources() {
|
|
||||||
err := filtersutil.ApplyToJSON(annotations.Filter{
|
|
||||||
Annotations: p.Annotations,
|
|
||||||
FsSlice: p.FieldSpecs,
|
|
||||||
}, r.Kunstructured)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
} else {
|
|
||||||
t, err := transform.NewMapTransformer(
|
|
||||||
p.FieldSpecs,
|
|
||||||
p.Annotations,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return t.Transform(m)
|
|
||||||
}
|
}
|
||||||
|
return m.ApplyFilter(annotations.Filter{
|
||||||
|
Annotations: p.Annotations,
|
||||||
|
FsSlice: p.FieldSpecs,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
|
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
|||||||
@@ -13,13 +13,10 @@ import (
|
|||||||
type ConfigMapGeneratorPlugin struct {
|
type ConfigMapGeneratorPlugin struct {
|
||||||
h *resmap.PluginHelpers
|
h *resmap.PluginHelpers
|
||||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
types.GeneratorOptions
|
|
||||||
types.ConfigMapArgs
|
types.ConfigMapArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConfigMapGeneratorPlugin) Config(
|
func (p *ConfigMapGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
|
||||||
h *resmap.PluginHelpers, config []byte) (err error) {
|
|
||||||
p.GeneratorOptions = types.GeneratorOptions{}
|
|
||||||
p.ConfigMapArgs = types.ConfigMapArgs{}
|
p.ConfigMapArgs = types.ConfigMapArgs{}
|
||||||
err = yaml.Unmarshal(config, p)
|
err = yaml.Unmarshal(config, p)
|
||||||
if p.ConfigMapArgs.Name == "" {
|
if p.ConfigMapArgs.Name == "" {
|
||||||
@@ -34,8 +31,7 @@ func (p *ConfigMapGeneratorPlugin) Config(
|
|||||||
|
|
||||||
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||||
return p.h.ResmapFactory().FromConfigMapArgs(
|
return p.h.ResmapFactory().FromConfigMapArgs(
|
||||||
kv.NewLoader(p.h.Loader(), p.h.Validator()),
|
kv.NewLoader(p.h.Loader(), p.h.Validator()), p.ConfigMapArgs)
|
||||||
&p.GeneratorOptions, p.ConfigMapArgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfigMapGeneratorPlugin() resmap.GeneratorPlugin {
|
func NewConfigMapGeneratorPlugin() resmap.GeneratorPlugin {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HashTransformerPlugin struct {
|
type HashTransformerPlugin struct {
|
||||||
hasher ifc.KunstructuredHasher
|
hasher ifc.KustHasher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HashTransformerPlugin) Config(
|
func (p *HashTransformerPlugin) Config(
|
||||||
@@ -24,10 +24,11 @@ func (p *HashTransformerPlugin) Config(
|
|||||||
func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
for _, res := range m.Resources() {
|
for _, res := range m.Resources() {
|
||||||
if res.NeedHashSuffix() {
|
if res.NeedHashSuffix() {
|
||||||
h, err := p.hasher.Hash(res)
|
h, err := res.Hash(p.hasher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
res.StorePreviousId()
|
||||||
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
|
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
339
api/builtins/HelmChartInflationGenerator.go
Normal file
339
api/builtins/HelmChartInflationGenerator.go
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
// Code generated by pluginator on HelmChartInflationGenerator; DO NOT EDIT.
|
||||||
|
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||||
|
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/imdario/mergo"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HelmChartInflationGeneratorPlugin is a plugin to generate resources
|
||||||
|
// from a remote or local helm chart.
|
||||||
|
type HelmChartInflationGeneratorPlugin struct {
|
||||||
|
h *resmap.PluginHelpers
|
||||||
|
types.HelmGlobals
|
||||||
|
types.HelmChart
|
||||||
|
tmpDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
var KustomizePlugin HelmChartInflationGeneratorPlugin
|
||||||
|
|
||||||
|
const (
|
||||||
|
valuesMergeOptionMerge = "merge"
|
||||||
|
valuesMergeOptionOverride = "override"
|
||||||
|
valuesMergeOptionReplace = "replace"
|
||||||
|
)
|
||||||
|
|
||||||
|
var legalMergeOptions = []string{
|
||||||
|
valuesMergeOptionMerge,
|
||||||
|
valuesMergeOptionOverride,
|
||||||
|
valuesMergeOptionReplace,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config uses the input plugin configurations `config` to setup the generator
|
||||||
|
// options
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) Config(
|
||||||
|
h *resmap.PluginHelpers, config []byte) (err error) {
|
||||||
|
if h.GeneralConfig() == nil {
|
||||||
|
return fmt.Errorf("unable to access general config")
|
||||||
|
}
|
||||||
|
if !h.GeneralConfig().HelmConfig.Enabled {
|
||||||
|
return fmt.Errorf("must specify --enable-helm")
|
||||||
|
}
|
||||||
|
if h.GeneralConfig().HelmConfig.Command == "" {
|
||||||
|
return fmt.Errorf("must specify --helm-command")
|
||||||
|
}
|
||||||
|
p.h = h
|
||||||
|
if err = yaml.Unmarshal(config, p); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return p.validateArgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This uses the real file system since tmpDir may be used
|
||||||
|
// by the helm subprocess. Cannot use a chroot jail or fake
|
||||||
|
// filesystem since we allow the user to use previously
|
||||||
|
// downloaded charts. This is safe since this plugin is
|
||||||
|
// owned by kustomize.
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) establishTmpDir() (err error) {
|
||||||
|
if p.tmpDir != "" {
|
||||||
|
// already done.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.tmpDir, err = ioutil.TempDir("", "kustomize-helm-")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) {
|
||||||
|
if p.Name == "" {
|
||||||
|
return fmt.Errorf("chart name cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChartHome might be consulted by the plugin (to read
|
||||||
|
// values files below it), so it must be located under
|
||||||
|
// the loader root (unless root restrictions are
|
||||||
|
// disabled, in which case this can be an absolute path).
|
||||||
|
if p.ChartHome == "" {
|
||||||
|
p.ChartHome = "charts"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ValuesFile may be consulted by the plugin, so it must
|
||||||
|
// be under the loader root (unless root restrictions are
|
||||||
|
// disabled).
|
||||||
|
if p.ValuesFile == "" {
|
||||||
|
p.ValuesFile = filepath.Join(p.ChartHome, p.Name, "values.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.errIfIllegalValuesMerge(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigHome is not loaded by the plugin, and can be located anywhere.
|
||||||
|
if p.ConfigHome == "" {
|
||||||
|
if err = p.establishTmpDir(); err != nil {
|
||||||
|
return errors.Wrap(
|
||||||
|
err, "unable to create tmp dir for HELM_CONFIG_HOME")
|
||||||
|
}
|
||||||
|
p.ConfigHome = filepath.Join(p.tmpDir, "helm")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) errIfIllegalValuesMerge() error {
|
||||||
|
if p.ValuesMerge == "" {
|
||||||
|
// Use the default.
|
||||||
|
p.ValuesMerge = valuesMergeOptionOverride
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, opt := range legalMergeOptions {
|
||||||
|
if p.ValuesMerge == opt {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("valuesMerge must be one of %v", legalMergeOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) absChartHome() string {
|
||||||
|
if filepath.IsAbs(p.ChartHome) {
|
||||||
|
return p.ChartHome
|
||||||
|
}
|
||||||
|
return filepath.Join(p.h.Loader().Root(), p.ChartHome)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) runHelmCommand(
|
||||||
|
args []string) ([]byte, error) {
|
||||||
|
stdout := new(bytes.Buffer)
|
||||||
|
stderr := new(bytes.Buffer)
|
||||||
|
cmd := exec.Command(p.h.GeneralConfig().HelmConfig.Command, args...)
|
||||||
|
cmd.Stdout = stdout
|
||||||
|
cmd.Stderr = stderr
|
||||||
|
env := []string{
|
||||||
|
fmt.Sprintf("HELM_CONFIG_HOME=%s", p.ConfigHome),
|
||||||
|
fmt.Sprintf("HELM_CACHE_HOME=%s/.cache", p.ConfigHome),
|
||||||
|
fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.ConfigHome)}
|
||||||
|
cmd.Env = append(os.Environ(), env...)
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
helm := p.h.GeneralConfig().HelmConfig.Command
|
||||||
|
err = errors.Wrap(
|
||||||
|
fmt.Errorf(
|
||||||
|
"unable to run: '%s %s' with env=%s (is '%s' installed?)",
|
||||||
|
helm, strings.Join(args, " "), env, helm),
|
||||||
|
stderr.String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return stdout.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// createNewMergedValuesFile replaces/merges original values file with ValuesInline.
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) createNewMergedValuesFile() (
|
||||||
|
path string, err error) {
|
||||||
|
if p.ValuesMerge == valuesMergeOptionMerge ||
|
||||||
|
p.ValuesMerge == valuesMergeOptionOverride {
|
||||||
|
if err = p.replaceValuesInline(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var b []byte
|
||||||
|
b, err = yaml.Marshal(p.ValuesInline)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return p.writeValuesBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) replaceValuesInline() error {
|
||||||
|
pValues, err := p.h.Loader().Load(p.ValuesFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chValues := make(map[string]interface{})
|
||||||
|
if err = yaml.Unmarshal(pValues, &chValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch p.ValuesMerge {
|
||||||
|
case valuesMergeOptionOverride:
|
||||||
|
err = mergo.Merge(
|
||||||
|
&chValues, p.ValuesInline, mergo.WithOverride)
|
||||||
|
case valuesMergeOptionMerge:
|
||||||
|
err = mergo.Merge(&chValues, p.ValuesInline)
|
||||||
|
}
|
||||||
|
p.ValuesInline = chValues
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyValuesFile to avoid branching. TODO: get rid of this.
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) copyValuesFile() (string, error) {
|
||||||
|
b, err := p.h.Loader().Load(p.ValuesFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return p.writeValuesBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a absolute path file in the tmp file system.
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) writeValuesBytes(
|
||||||
|
b []byte) (string, error) {
|
||||||
|
if err := p.establishTmpDir(); err != nil {
|
||||||
|
return "", fmt.Errorf("cannot create tmp dir to write helm values")
|
||||||
|
}
|
||||||
|
path := filepath.Join(p.tmpDir, p.Name+"-kustomize-values.yaml")
|
||||||
|
return path, ioutil.WriteFile(path, b, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) cleanup() {
|
||||||
|
if p.tmpDir != "" {
|
||||||
|
os.RemoveAll(p.tmpDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate implements generator
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) Generate() (rm resmap.ResMap, err error) {
|
||||||
|
defer p.cleanup()
|
||||||
|
if err = p.checkHelmVersion(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if path, exists := p.chartExistsLocally(); !exists {
|
||||||
|
if p.Repo == "" {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"no repo specified for pull, no chart found at '%s'", path)
|
||||||
|
}
|
||||||
|
if _, err := p.runHelmCommand(p.pullCommand()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(p.ValuesInline) > 0 {
|
||||||
|
p.ValuesFile, err = p.createNewMergedValuesFile()
|
||||||
|
} else {
|
||||||
|
p.ValuesFile, err = p.copyValuesFile()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var stdout []byte
|
||||||
|
stdout, err = p.runHelmCommand(p.templateCommand())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rm, err = p.h.ResmapFactory().NewResMapFromBytes(stdout)
|
||||||
|
if err == nil {
|
||||||
|
return rm, nil
|
||||||
|
}
|
||||||
|
// try to remove the contents before first "---" because
|
||||||
|
// helm may produce messages to stdout before it
|
||||||
|
stdoutStr := string(stdout)
|
||||||
|
if idx := strings.Index(stdoutStr, "---"); idx != -1 {
|
||||||
|
return p.h.ResmapFactory().NewResMapFromBytes([]byte(stdoutStr[idx:]))
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) templateCommand() []string {
|
||||||
|
args := []string{"template"}
|
||||||
|
if p.ReleaseName != "" {
|
||||||
|
args = append(args, p.ReleaseName)
|
||||||
|
}
|
||||||
|
if p.Namespace != "" {
|
||||||
|
args = append(args, "--namespace", p.Namespace)
|
||||||
|
}
|
||||||
|
args = append(args, filepath.Join(p.absChartHome(), p.Name))
|
||||||
|
if p.ValuesFile != "" {
|
||||||
|
args = append(args, "--values", p.ValuesFile)
|
||||||
|
}
|
||||||
|
if p.ReleaseName == "" {
|
||||||
|
// AFAICT, this doesn't work as intended due to a bug in helm.
|
||||||
|
// See https://github.com/helm/helm/issues/6019
|
||||||
|
// I've tried placing the flag before and after the name argument.
|
||||||
|
args = append(args, "--generate-name")
|
||||||
|
}
|
||||||
|
if p.IncludeCRDs {
|
||||||
|
args = append(args, "--include-crds")
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) pullCommand() []string {
|
||||||
|
args := []string{
|
||||||
|
"pull",
|
||||||
|
"--untar",
|
||||||
|
"--untardir", p.absChartHome(),
|
||||||
|
"--repo", p.Repo,
|
||||||
|
p.Name}
|
||||||
|
if p.Version != "" {
|
||||||
|
args = append(args, "--version", p.Version)
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// chartExistsLocally will return true if the chart does exist in
|
||||||
|
// local chart home.
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) chartExistsLocally() (string, bool) {
|
||||||
|
path := filepath.Join(p.absChartHome(), p.Name)
|
||||||
|
s, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return path, s.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHelmVersion will return an error if the helm version is not V3
|
||||||
|
func (p *HelmChartInflationGeneratorPlugin) checkHelmVersion() error {
|
||||||
|
stdout, err := p.runHelmCommand([]string{"version", "-c", "--short"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r, err := regexp.Compile(`v?\d+(\.\d+)+`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := r.FindString(string(stdout))
|
||||||
|
if v == "" {
|
||||||
|
return fmt.Errorf("cannot find version string in %s", string(stdout))
|
||||||
|
}
|
||||||
|
if v[0] == 'v' {
|
||||||
|
v = v[1:]
|
||||||
|
}
|
||||||
|
majorVersion := strings.Split(v, ".")[0]
|
||||||
|
if majorVersion != "3" {
|
||||||
|
return fmt.Errorf("this plugin requires helm V3 but got v%s", v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHelmChartInflationGeneratorPlugin() resmap.GeneratorPlugin {
|
||||||
|
return &HelmChartInflationGeneratorPlugin{}
|
||||||
|
}
|
||||||
33
api/builtins/IAMPolicyGenerator.go
Normal file
33
api/builtins/IAMPolicyGenerator.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Code generated by pluginator on IAMPolicyGenerator; DO NOT EDIT.
|
||||||
|
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||||
|
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/iampolicygenerator"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IAMPolicyGeneratorPlugin struct {
|
||||||
|
types.IAMPolicyGeneratorArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IAMPolicyGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
|
||||||
|
p.IAMPolicyGeneratorArgs = types.IAMPolicyGeneratorArgs{}
|
||||||
|
err = yaml.Unmarshal(config, p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IAMPolicyGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||||
|
r := resmap.New()
|
||||||
|
err := r.ApplyFilter(iampolicygenerator.Filter{
|
||||||
|
IAMPolicyGenerator: p.IAMPolicyGeneratorArgs,
|
||||||
|
})
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAMPolicyGeneratorPlugin() resmap.GeneratorPlugin {
|
||||||
|
return &IAMPolicyGeneratorPlugin{}
|
||||||
|
}
|
||||||
@@ -4,14 +4,9 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"sigs.k8s.io/kustomize/api/filters/imagetag"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,156 +25,15 @@ func (p *ImageTagTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
for _, r := range m.Resources() {
|
if err := m.ApplyFilter(imagetag.LegacyFilter{
|
||||||
for _, path := range p.FieldSpecs {
|
ImageTag: p.ImageTag,
|
||||||
if !r.OrgId().IsSelected(&path.Gvk) {
|
}); err != nil {
|
||||||
continue
|
return err
|
||||||
}
|
|
||||||
err := transform.MutateField(
|
|
||||||
r.Map(), path.PathSlice(), false, p.mutateImage)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Kept for backward compatibility
|
|
||||||
if err := p.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return m.ApplyFilter(imagetag.Filter{
|
||||||
}
|
ImageTag: p.ImageTag,
|
||||||
|
FsSlice: p.FieldSpecs,
|
||||||
func (p *ImageTagTransformerPlugin) mutateImage(in interface{}) (interface{}, error) {
|
})
|
||||||
original, ok := in.(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("image path is not of type string but %T", in)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isImageMatched(original, p.ImageTag.Name) {
|
|
||||||
return original, nil
|
|
||||||
}
|
|
||||||
name, tag := split(original)
|
|
||||||
if p.ImageTag.NewName != "" {
|
|
||||||
name = p.ImageTag.NewName
|
|
||||||
}
|
|
||||||
if p.ImageTag.NewTag != "" {
|
|
||||||
tag = ":" + p.ImageTag.NewTag
|
|
||||||
}
|
|
||||||
if p.ImageTag.Digest != "" {
|
|
||||||
tag = "@" + p.ImageTag.Digest
|
|
||||||
}
|
|
||||||
return name + tag, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findAndReplaceImage replaces the image name and
|
|
||||||
// tags inside one object.
|
|
||||||
// It searches the object for container session
|
|
||||||
// then loops though all images inside containers
|
|
||||||
// session, finds matched ones and update the
|
|
||||||
// image name and tag name
|
|
||||||
func (p *ImageTagTransformerPlugin) findAndReplaceImage(obj map[string]interface{}) error {
|
|
||||||
paths := []string{"containers", "initContainers"}
|
|
||||||
updated := false
|
|
||||||
for _, path := range paths {
|
|
||||||
containers, found := obj[path]
|
|
||||||
if found && containers != nil {
|
|
||||||
if _, err := p.updateContainers(containers); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !updated {
|
|
||||||
return p.findContainers(obj)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ImageTagTransformerPlugin) updateContainers(in interface{}) (interface{}, error) {
|
|
||||||
containers, ok := in.([]interface{})
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"containers path is not of type []interface{} but %T", in)
|
|
||||||
}
|
|
||||||
for i := range containers {
|
|
||||||
container := containers[i].(map[string]interface{})
|
|
||||||
containerImage, found := container["image"]
|
|
||||||
if !found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
imageName := containerImage.(string)
|
|
||||||
if isImageMatched(imageName, p.ImageTag.Name) {
|
|
||||||
newImage, err := p.mutateImage(imageName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
container["image"] = newImage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return containers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ImageTagTransformerPlugin) findContainers(obj map[string]interface{}) error {
|
|
||||||
for key := range obj {
|
|
||||||
switch typedV := obj[key].(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
err := p.findAndReplaceImage(typedV)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
for i := range typedV {
|
|
||||||
item := typedV[i]
|
|
||||||
typedItem, ok := item.(map[string]interface{})
|
|
||||||
if ok {
|
|
||||||
err := p.findAndReplaceImage(typedItem)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isImageMatched(s, t string) bool {
|
|
||||||
// Tag values are limited to [a-zA-Z0-9_.{}-].
|
|
||||||
// Some tools like Bazel rules_k8s allow tag patterns with {} characters.
|
|
||||||
// More info: https://github.com/bazelbuild/rules_k8s/pull/423
|
|
||||||
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.{}-]*)?$")
|
|
||||||
return pattern.MatchString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// split separates and returns the name and tag parts
|
|
||||||
// from the image string using either colon `:` or at `@` separators.
|
|
||||||
// Note that the returned tag keeps its separator.
|
|
||||||
func split(imageName string) (name string, tag string) {
|
|
||||||
// check if image name contains a domain
|
|
||||||
// if domain is present, ignore domain and check for `:`
|
|
||||||
ic := -1
|
|
||||||
if slashIndex := strings.Index(imageName, "/"); slashIndex < 0 {
|
|
||||||
ic = strings.LastIndex(imageName, ":")
|
|
||||||
} else {
|
|
||||||
lastIc := strings.LastIndex(imageName[slashIndex:], ":")
|
|
||||||
// set ic only if `:` is present
|
|
||||||
if lastIc > 0 {
|
|
||||||
ic = slashIndex + lastIc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ia := strings.LastIndex(imageName, "@")
|
|
||||||
if ic < 0 && ia < 0 {
|
|
||||||
return imageName, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
i := ic
|
|
||||||
if ia > 0 {
|
|
||||||
i = ia
|
|
||||||
}
|
|
||||||
|
|
||||||
name = imageName[:i]
|
|
||||||
tag = imageName[i:]
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewImageTagTransformerPlugin() resmap.TransformerPlugin {
|
func NewImageTagTransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
// Code generated by pluginator on InventoryTransformer; DO NOT EDIT.
|
|
||||||
// pluginator {unknown 1970-01-01T00:00:00Z }
|
|
||||||
|
|
||||||
package builtins
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/hasher"
|
|
||||||
"sigs.k8s.io/kustomize/api/inventory"
|
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InventoryTransformerPlugin struct {
|
|
||||||
h *resmap.PluginHelpers
|
|
||||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
|
||||||
Policy string `json:"policy,omitempty" yaml:"policy,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *InventoryTransformerPlugin) Config(
|
|
||||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
|
||||||
p.h = h
|
|
||||||
err = yaml.Unmarshal(c, p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if p.Policy == "" {
|
|
||||||
p.Policy = types.GarbageIgnore.String()
|
|
||||||
}
|
|
||||||
if p.Policy != types.GarbageCollect.String() &&
|
|
||||||
p.Policy != types.GarbageIgnore.String() {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"unrecognized garbagePolicy '%s'", p.Policy)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform generates an inventory object from the input ResMap.
|
|
||||||
// This ConfigMap supports the pruning command in
|
|
||||||
// the client side tool proposed here:
|
|
||||||
// https://github.com/kubernetes/enhancements/pull/810
|
|
||||||
//
|
|
||||||
// The inventory data is written to the ConfigMap's
|
|
||||||
// annotations, rather than to the key-value pairs in
|
|
||||||
// the ConfigMap's data field, since
|
|
||||||
// 1. Keys in a ConfigMap's data field are too
|
|
||||||
// constrained for this purpose.
|
|
||||||
// 2. Using annotations allow any object to be used,
|
|
||||||
// not just a ConfigMap, should some other object
|
|
||||||
// (e.g. some App object) become more desirable
|
|
||||||
// for this purpose.
|
|
||||||
func (p *InventoryTransformerPlugin) Transform(m resmap.ResMap) error {
|
|
||||||
|
|
||||||
inv, h, err := makeInventory(m)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
args := types.ConfigMapArgs{}
|
|
||||||
args.Name = p.Name
|
|
||||||
args.Namespace = p.Namespace
|
|
||||||
opts := &types.GeneratorOptions{
|
|
||||||
Annotations: make(map[string]string),
|
|
||||||
}
|
|
||||||
opts.Annotations[inventory.HashAnnotation] = h
|
|
||||||
err = inv.UpdateAnnotations(opts.Annotations)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cm, err := p.h.ResmapFactory().RF().MakeConfigMap(
|
|
||||||
kv.NewLoader(p.h.Loader(), p.h.Validator()), opts, &args)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Policy == types.GarbageCollect.String() {
|
|
||||||
for _, byeBye := range m.AllIds() {
|
|
||||||
m.Remove(byeBye)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m.Append(cm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeInventory(m resmap.ResMap) (
|
|
||||||
inv *inventory.Inventory, hash string, err error) {
|
|
||||||
inv = inventory.NewInventory()
|
|
||||||
var keys []string
|
|
||||||
for _, r := range m.Resources() {
|
|
||||||
ns := r.GetNamespace()
|
|
||||||
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
|
|
||||||
if _, ok := inv.Current[item]; ok {
|
|
||||||
return nil, "", fmt.Errorf(
|
|
||||||
"item '%v' already in inventory", item)
|
|
||||||
}
|
|
||||||
inv.Current[item], err = computeRefs(r, m)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
keys = append(keys, item.String())
|
|
||||||
}
|
|
||||||
h, err := hasher.SortArrayAndComputeHash(keys)
|
|
||||||
return inv, h, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeRefs(
|
|
||||||
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
|
|
||||||
for _, refid := range r.GetRefBy() {
|
|
||||||
ref, err := m.GetByCurrentId(refid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
refs = append(
|
|
||||||
refs,
|
|
||||||
resid.NewResIdWithNamespace(
|
|
||||||
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInventoryTransformerPlugin() resmap.TransformerPlugin {
|
|
||||||
return &InventoryTransformerPlugin{}
|
|
||||||
}
|
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
package builtins
|
package builtins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/labels"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
@@ -24,14 +24,13 @@ func (p *LabelTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
t, err := transform.NewMapTransformer(
|
if len(p.Labels) == 0 {
|
||||||
p.FieldSpecs,
|
return nil
|
||||||
p.Labels,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return t.Transform(m)
|
return m.ApplyFilter(labels.Filter{
|
||||||
|
Labels: p.Labels,
|
||||||
|
FsSlice: p.FieldSpecs,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
|
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
|||||||
@@ -7,12 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/filters/namespace"
|
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filtersutil"
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,11 +16,6 @@ import (
|
|||||||
type NamespaceTransformerPlugin struct {
|
type NamespaceTransformerPlugin struct {
|
||||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
|
|
||||||
// YAMLSupport can be set to true to use the kyaml filter instead of the
|
|
||||||
// kunstruct transformer.
|
|
||||||
// TODO: change the default to use kyaml when it is stable
|
|
||||||
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NamespaceTransformerPlugin) Config(
|
func (p *NamespaceTransformerPlugin) Config(
|
||||||
@@ -39,112 +30,26 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if len(r.Map()) == 0 {
|
if r.IsNilOrEmpty() {
|
||||||
// Don't mutate empty objects?
|
// Don't mutate empty objects?
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
r.StorePreviousId()
|
||||||
id := r.OrgId()
|
if err := r.ApplyFilter(namespace.Filter{
|
||||||
|
Namespace: p.Namespace,
|
||||||
if !p.YAMLSupport {
|
FsSlice: p.FieldSpecs,
|
||||||
// use the old style transform
|
}); err != nil {
|
||||||
applicableFs := p.applicableFieldSpecs(id)
|
return err
|
||||||
|
|
||||||
for _, fs := range applicableFs {
|
|
||||||
err := transform.MutateField(
|
|
||||||
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
|
||||||
p.changeNamespace(r))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// use the new style transform
|
|
||||||
err := filtersutil.ApplyToJSON(namespace.Filter{
|
|
||||||
Namespace: p.Namespace,
|
|
||||||
FsSlice: p.FieldSpecs,
|
|
||||||
}, r.Kunstructured)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
|
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
|
||||||
if len(matches) != 1 {
|
if len(matches) != 1 {
|
||||||
return fmt.Errorf("namespace transformation produces ID conflict: %+v", matches)
|
return fmt.Errorf(
|
||||||
|
"namespace transformation produces ID conflict: %+v", matches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const metaNamespace = "metadata/namespace"
|
|
||||||
|
|
||||||
// Special casing metadata.namespace since
|
|
||||||
// all objects have it, even "ClusterKind" objects
|
|
||||||
// that don't exist in a namespace (the Namespace
|
|
||||||
// object itself doesn't live in a namespace).
|
|
||||||
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []types.FieldSpec {
|
|
||||||
var res []types.FieldSpec
|
|
||||||
for _, fs := range p.FieldSpecs {
|
|
||||||
if id.IsSelected(&fs.Gvk) && (fs.Path != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
|
|
||||||
res = append(res, fs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *NamespaceTransformerPlugin) changeNamespace(
|
|
||||||
_ *resource.Resource) func(in interface{}) (interface{}, error) {
|
|
||||||
return func(in interface{}) (interface{}, error) {
|
|
||||||
switch in.(type) {
|
|
||||||
case string:
|
|
||||||
// will happen when the metadata/namespace
|
|
||||||
// value is replaced
|
|
||||||
return p.Namespace, nil
|
|
||||||
case []interface{}:
|
|
||||||
l, _ := in.([]interface{})
|
|
||||||
for idx, item := range l {
|
|
||||||
switch item.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
// Will happen when mutating the subjects
|
|
||||||
// field of ClusterRoleBinding and RoleBinding
|
|
||||||
inMap, _ := item.(map[string]interface{})
|
|
||||||
if _, ok := inMap["name"]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name, ok := inMap["name"].(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// The only case we need to force the namespace
|
|
||||||
// if for the "service account". "default" is
|
|
||||||
// kind of hardcoded here for right now.
|
|
||||||
if name != "default" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
inMap["namespace"] = p.Namespace
|
|
||||||
l[idx] = inMap
|
|
||||||
default:
|
|
||||||
// nothing to do for right now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in, nil
|
|
||||||
case map[string]interface{}:
|
|
||||||
// Will happen if the createField=true
|
|
||||||
// when the namespace is added to the
|
|
||||||
// object
|
|
||||||
inMap := in.(map[string]interface{})
|
|
||||||
if len(inMap) == 0 {
|
|
||||||
return p.Namespace, nil
|
|
||||||
} else {
|
|
||||||
return in, nil
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return in, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
|
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
|
||||||
return &NamespaceTransformerPlugin{}
|
return &NamespaceTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ import (
|
|||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PatchJson6902TransformerPlugin struct {
|
type PatchJson6902TransformerPlugin struct {
|
||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
decodedPatch jsonpatch.Patch
|
decodedPatch jsonpatch.Patch
|
||||||
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchJson6902TransformerPlugin) Config(
|
func (p *PatchJson6902TransformerPlugin) Config(
|
||||||
@@ -70,29 +71,33 @@ func (p *PatchJson6902TransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
id := resid.NewResIdWithNamespace(
|
if p.Target == nil {
|
||||||
resid.Gvk{
|
return fmt.Errorf("must specify a target for patch %s", p.JsonOp)
|
||||||
Group: p.Target.Group,
|
}
|
||||||
Version: p.Target.Version,
|
resources, err := m.Select(*p.Target)
|
||||||
Kind: p.Target.Kind,
|
|
||||||
},
|
|
||||||
p.Target.Name,
|
|
||||||
p.Target.Namespace,
|
|
||||||
)
|
|
||||||
obj, err := m.GetById(id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rawObj, err := obj.MarshalJSON()
|
for _, res := range resources {
|
||||||
if err != nil {
|
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
||||||
return err
|
|
||||||
|
err = res.ApplyFilter(patchjson6902.Filter{
|
||||||
|
Patch: p.JsonOp,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations := res.GetAnnotations()
|
||||||
|
for key, value := range internalAnnotations {
|
||||||
|
annotations[key] = value
|
||||||
|
}
|
||||||
|
err = res.SetAnnotations(annotations)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
return nil
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(
|
|
||||||
err, "failed to apply json patch '%s'", p.JsonOp)
|
|
||||||
}
|
|
||||||
return obj.UnmarshalJSON(modifiedObj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {
|
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PatchStrategicMergeTransformerPlugin struct {
|
type PatchStrategicMergeTransformerPlugin struct {
|
||||||
h *resmap.PluginHelpers
|
|
||||||
loadedPatches []*resource.Resource
|
loadedPatches []*resource.Resource
|
||||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
@@ -21,7 +20,6 @@ type PatchStrategicMergeTransformerPlugin struct {
|
|||||||
|
|
||||||
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
func (p *PatchStrategicMergeTransformerPlugin) Config(
|
||||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||||
p.h = h
|
|
||||||
err = yaml.Unmarshal(c, p)
|
err = yaml.Unmarshal(c, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -30,57 +28,58 @@ func (p *PatchStrategicMergeTransformerPlugin) Config(
|
|||||||
return fmt.Errorf("empty file path and empty patch content")
|
return fmt.Errorf("empty file path and empty patch content")
|
||||||
}
|
}
|
||||||
if len(p.Paths) != 0 {
|
if len(p.Paths) != 0 {
|
||||||
for _, onePath := range p.Paths {
|
patches, err := loadFromPaths(h, p.Paths)
|
||||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
|
|
||||||
if err == nil {
|
|
||||||
p.loadedPatches = append(p.loadedPatches, res...)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res, err = p.h.ResmapFactory().RF().SliceFromPatches(
|
|
||||||
p.h.Loader(), []types.PatchStrategicMerge{onePath})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.loadedPatches = append(p.loadedPatches, res...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.Patches != "" {
|
|
||||||
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.loadedPatches = append(p.loadedPatches, res...)
|
p.loadedPatches = append(p.loadedPatches, patches...)
|
||||||
|
}
|
||||||
|
if p.Patches != "" {
|
||||||
|
patches, err := h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.loadedPatches = append(p.loadedPatches, patches...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.loadedPatches) == 0 {
|
if len(p.loadedPatches) == 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadFromPaths(
|
||||||
|
h *resmap.PluginHelpers,
|
||||||
|
paths []types.PatchStrategicMerge) (
|
||||||
|
result []*resource.Resource, err error) {
|
||||||
|
var patches []*resource.Resource
|
||||||
|
for _, path := range paths {
|
||||||
|
// For legacy reasons, attempt to treat the path string as
|
||||||
|
// actual patch content.
|
||||||
|
patches, err = h.ResmapFactory().RF().SliceFromBytes([]byte(path))
|
||||||
|
if err != nil {
|
||||||
|
// Failing that, treat it as a file path.
|
||||||
|
patches, err = h.ResmapFactory().RF().SliceFromPatches(
|
||||||
|
h.Loader(), []types.PatchStrategicMerge{path})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = append(result, patches...)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
|
for _, patch := range p.loadedPatches {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, patch := range patches.Resources() {
|
|
||||||
target, err := m.GetById(patch.OrgId())
|
target, err := m.GetById(patch.OrgId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = target.Patch(patch.Kunstructured)
|
if err = m.ApplySmPatch(
|
||||||
if err != nil {
|
resource.MakeIdSet([]*resource.Resource{target}), patch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// remove the resource from resmap
|
|
||||||
// when the patch is to $patch: delete that target
|
|
||||||
if len(target.Map()) == 0 {
|
|
||||||
err = m.Remove(target.CurId())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/pkg/errors"
|
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,103 +22,109 @@ type PatchTransformerPlugin struct {
|
|||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchTransformerPlugin) Config(
|
func (p *PatchTransformerPlugin) Config(
|
||||||
h *resmap.PluginHelpers, c []byte) (err error) {
|
h *resmap.PluginHelpers, c []byte) error {
|
||||||
err = yaml.Unmarshal(c, p)
|
err := yaml.Unmarshal(c, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
p.Patch = strings.TrimSpace(p.Patch)
|
||||||
if p.Patch == "" && p.Path == "" {
|
if p.Patch == "" && p.Path == "" {
|
||||||
err = fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"must specify one of patch and path in\n%s", string(c))
|
"must specify one of patch and path in\n%s", string(c))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if p.Patch != "" && p.Path != "" {
|
if p.Patch != "" && p.Path != "" {
|
||||||
err = fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"patch and path can't be set at the same time\n%s", string(c))
|
"patch and path can't be set at the same time\n%s", string(c))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var in []byte
|
|
||||||
if p.Path != "" {
|
if p.Path != "" {
|
||||||
in, err = h.Loader().Load(p.Path)
|
loaded, loadErr := h.Loader().Load(p.Path)
|
||||||
if err != nil {
|
if loadErr != nil {
|
||||||
return
|
return loadErr
|
||||||
}
|
}
|
||||||
}
|
p.Patch = string(loaded)
|
||||||
if p.Patch != "" {
|
|
||||||
in = []byte(p.Patch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
patchSM, errSM := h.ResmapFactory().RF().FromBytes(in)
|
patchSM, errSM := h.ResmapFactory().RF().FromBytes([]byte(p.Patch))
|
||||||
patchJson, errJson := jsonPatchFromBytes(in)
|
patchJson, errJson := jsonPatchFromBytes([]byte(p.Patch))
|
||||||
|
if (errSM == nil && errJson == nil) ||
|
||||||
|
(patchSM != nil && patchJson != nil) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"illegally qualifies as both an SM and JSON patch: [%v]",
|
||||||
|
p.Patch)
|
||||||
|
}
|
||||||
if errSM != nil && errJson != nil {
|
if errSM != nil && errJson != nil {
|
||||||
err = fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
|
"unable to parse SM or JSON patch from [%v]", p.Patch)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if errSM == nil && errJson != nil {
|
if errSM == nil {
|
||||||
p.loadedPatch = patchSM
|
p.loadedPatch = patchSM
|
||||||
}
|
if p.Options["allowNameChange"] {
|
||||||
if errJson == nil && errSM != nil {
|
p.loadedPatch.AllowNameChange()
|
||||||
|
}
|
||||||
|
if p.Options["allowKindChange"] {
|
||||||
|
p.loadedPatch.AllowKindChange()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
p.decodedPatch = patchJson
|
p.decodedPatch = patchJson
|
||||||
}
|
}
|
||||||
if patchSM != nil && patchJson != nil {
|
|
||||||
err = fmt.Errorf(
|
|
||||||
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
if p.loadedPatch != nil && p.Target == nil {
|
if p.loadedPatch == nil {
|
||||||
target, err := m.GetById(p.loadedPatch.OrgId())
|
return p.transformJson6902(m, p.decodedPatch)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = target.Patch(p.loadedPatch.Kunstructured)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
// The patch was a strategic merge patch
|
||||||
|
return p.transformStrategicMerge(m, p.loadedPatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// transformStrategicMerge applies the provided strategic merge patch
|
||||||
|
// to all the resources in the ResMap that match either the Target or
|
||||||
|
// the identifier of the patch.
|
||||||
|
func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch *resource.Resource) error {
|
||||||
|
if p.Target == nil {
|
||||||
|
target, err := m.GetById(patch.OrgId())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return target.ApplySmPatch(patch)
|
||||||
|
}
|
||||||
|
selected, err := m.Select(*p.Target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.ApplySmPatch(resource.MakeIdSet(selected), patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// transformJson6902 applies the provided json6902 patch
|
||||||
|
// to all the resources in the ResMap that match the Target.
|
||||||
|
func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error {
|
||||||
if p.Target == nil {
|
if p.Target == nil {
|
||||||
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
||||||
}
|
}
|
||||||
|
|
||||||
resources, err := m.Select(*p.Target)
|
resources, err := m.Select(*p.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, res := range resources {
|
for _, res := range resources {
|
||||||
if p.decodedPatch != nil {
|
res.StorePreviousId()
|
||||||
rawObj, err := res.MarshalJSON()
|
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
||||||
if err != nil {
|
err = res.ApplyFilter(patchjson6902.Filter{
|
||||||
return err
|
Patch: p.Patch,
|
||||||
}
|
})
|
||||||
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return errors.Wrapf(
|
|
||||||
err, "failed to apply json patch '%s'", p.Patch)
|
|
||||||
}
|
|
||||||
err = res.UnmarshalJSON(modifiedObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if p.loadedPatch != nil {
|
|
||||||
patchCopy := p.loadedPatch.DeepCopy()
|
annotations := res.GetAnnotations()
|
||||||
patchCopy.SetName(res.GetName())
|
for key, value := range internalAnnotations {
|
||||||
patchCopy.SetNamespace(res.GetNamespace())
|
annotations[key] = value
|
||||||
patchCopy.SetGvk(res.GetGvk())
|
|
||||||
err = res.Patch(patchCopy.Kunstructured)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
err = res.SetAnnotations(annotations)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,31 +5,27 @@ package builtins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add the given prefix and suffix to the field.
|
// Add the given prefix and suffix to the field.
|
||||||
type PrefixSuffixTransformerPlugin struct {
|
type PrefixSuffixTransformerPlugin struct {
|
||||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not placed in a file yet due to lack of demand.
|
// A Gvk skip list for prefix/suffix modification.
|
||||||
var prefixSuffixFieldSpecsToSkip = []types.FieldSpec{
|
// hard coded for now - eventually should be part of config.
|
||||||
{
|
var prefixSuffixFieldSpecsToSkip = types.FsSlice{
|
||||||
Gvk: resid.Gvk{Kind: "CustomResourceDefinition"},
|
{Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}},
|
||||||
},
|
{Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}},
|
||||||
{
|
{Gvk: resid.Gvk{Kind: "Namespace"}},
|
||||||
Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) Config(
|
func (p *PrefixSuffixTransformerPlugin) Config(
|
||||||
@@ -48,46 +44,40 @@ func (p *PrefixSuffixTransformerPlugin) Config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
|
|
||||||
// Even if both the Prefix and Suffix are empty we want
|
// Even if both the Prefix and Suffix are empty we want
|
||||||
// to proceed with the transformation. This allows to add contextual
|
// to proceed with the transformation. This allows to add contextual
|
||||||
// information to the resources (AddNamePrefix and AddNameSuffix).
|
// information to the resources (AddNamePrefix and AddNameSuffix).
|
||||||
|
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
|
// TODO: move this test into the filter (i.e. make a better filter)
|
||||||
if p.shouldSkip(r.OrgId()) {
|
if p.shouldSkip(r.OrgId()) {
|
||||||
// Don't change the actual definition
|
|
||||||
// of a CRD.
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
id := r.OrgId()
|
id := r.OrgId()
|
||||||
// current default configuration contains
|
// current default configuration contains
|
||||||
// only one entry: "metadata/name" with no GVK
|
// only one entry: "metadata/name" with no GVK
|
||||||
for _, path := range p.FieldSpecs {
|
for _, fs := range p.FieldSpecs {
|
||||||
if !id.IsSelected(&path.Gvk) {
|
// TODO: this is redundant to filter (but needed for now)
|
||||||
// With the currrent default configuration,
|
if !id.IsSelected(&fs.Gvk) {
|
||||||
// because no Gvk is specified, so a wild
|
|
||||||
// card
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// TODO: move this test into the filter.
|
||||||
if smellsLikeANameChange(&path) {
|
if smellsLikeANameChange(&fs) {
|
||||||
// "metadata/name" is the only field.
|
// "metadata/name" is the only field.
|
||||||
// this will add a prefix and a suffix
|
// this will add a prefix and a suffix
|
||||||
// to the resource even if those are
|
// to the resource even if those are
|
||||||
// empty
|
// empty
|
||||||
|
|
||||||
r.AddNamePrefix(p.Prefix)
|
r.AddNamePrefix(p.Prefix)
|
||||||
r.AddNameSuffix(p.Suffix)
|
r.AddNameSuffix(p.Suffix)
|
||||||
|
if p.Prefix != "" || p.Suffix != "" {
|
||||||
|
r.StorePreviousId()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if err := r.ApplyFilter(prefixsuffix.Filter{
|
||||||
// the addPrefixSuffix method will not
|
Prefix: p.Prefix,
|
||||||
// change the name if both the prefix and suffix
|
Suffix: p.Suffix,
|
||||||
// are empty.
|
FieldSpec: fs,
|
||||||
err := transform.MutateField(
|
}); err != nil {
|
||||||
r.Map(),
|
|
||||||
path.PathSlice(),
|
|
||||||
path.CreateIfNotPresent,
|
|
||||||
p.addPrefixSuffix)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +89,7 @@ func smellsLikeANameChange(fs *types.FieldSpec) bool {
|
|||||||
return fs.Path == "metadata/name"
|
return fs.Path == "metadata/name"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
|
func (p *PrefixSuffixTransformerPlugin) shouldSkip(id resid.ResId) bool {
|
||||||
id resid.ResId) bool {
|
|
||||||
for _, path := range prefixSuffixFieldSpecsToSkip {
|
for _, path := range prefixSuffixFieldSpecsToSkip {
|
||||||
if id.IsSelected(&path.Gvk) {
|
if id.IsSelected(&path.Gvk) {
|
||||||
return true
|
return true
|
||||||
@@ -109,15 +98,6 @@ func (p *PrefixSuffixTransformerPlugin) shouldSkip(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
|
|
||||||
in interface{}) (interface{}, error) {
|
|
||||||
s, ok := in.(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("%#v is expected to be %T", in, s)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
|
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
|
||||||
return &PrefixSuffixTransformerPlugin{}
|
return &PrefixSuffixTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
59
api/builtins/ReplacementTransformer.go
Normal file
59
api/builtins/ReplacementTransformer.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Code generated by pluginator on ReplacementTransformer; DO NOT EDIT.
|
||||||
|
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||||
|
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/replacement"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Replace values in targets with values from a source
|
||||||
|
type ReplacementTransformerPlugin struct {
|
||||||
|
ReplacementList []types.ReplacementField `json:"replacements,omitempty" yaml:"replacements,omitempty"`
|
||||||
|
Replacements []types.Replacement `json:"omitempty" yaml:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReplacementTransformerPlugin) Config(
|
||||||
|
h *resmap.PluginHelpers, c []byte) (err error) {
|
||||||
|
p.ReplacementList = []types.ReplacementField{}
|
||||||
|
if err := yaml.Unmarshal(c, p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range p.ReplacementList {
|
||||||
|
if r.Path != "" && (r.Source != nil || len(r.Targets) != 0) {
|
||||||
|
return fmt.Errorf("cannot specify both path and inline replacement")
|
||||||
|
}
|
||||||
|
if r.Path != "" {
|
||||||
|
// load the replacement from the path
|
||||||
|
content, err := h.Loader().Load(r.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repl := types.Replacement{}
|
||||||
|
if err := yaml.Unmarshal(content, &repl); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Replacements = append(p.Replacements, repl)
|
||||||
|
} else {
|
||||||
|
// replacement information is already loaded
|
||||||
|
p.Replacements = append(p.Replacements, r.Replacement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReplacementTransformerPlugin) Transform(m resmap.ResMap) (err error) {
|
||||||
|
return m.ApplyFilter(replacement.Filter{
|
||||||
|
Replacements: p.Replacements,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReplacementTransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
return &ReplacementTransformerPlugin{}
|
||||||
|
}
|
||||||
@@ -6,11 +6,10 @@ package builtins
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/transform"
|
"sigs.k8s.io/kustomize/api/filters/replicacount"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,18 +29,22 @@ func (p *ReplicaCountTransformerPlugin) Config(
|
|||||||
|
|
||||||
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
found := false
|
found := false
|
||||||
for i, replicaSpec := range p.FieldSpecs {
|
for _, fs := range p.FieldSpecs {
|
||||||
matcher := p.createMatcher(i)
|
matcher := p.createMatcher(fs)
|
||||||
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
|
resList := m.GetMatchingResourcesByAnyId(matcher)
|
||||||
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher)
|
if len(resList) > 0 {
|
||||||
|
|
||||||
for _, res := range append(matchOriginal, matchCurrent...) {
|
|
||||||
found = true
|
found = true
|
||||||
err := transform.MutateField(
|
for _, r := range resList {
|
||||||
res.Map(), replicaSpec.PathSlice(),
|
// There are redundant checks in the filter
|
||||||
replicaSpec.CreateIfNotPresent, p.addReplicas)
|
// that we'll live with until resolution of
|
||||||
if err != nil {
|
// https://github.com/kubernetes-sigs/kustomize/issues/2506
|
||||||
return err
|
err := r.ApplyFilter(replicacount.Filter{
|
||||||
|
Replica: p.Replica,
|
||||||
|
FieldSpec: fs,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,30 +62,12 @@ func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Match Replica.Name and FieldSpec
|
// Match Replica.Name and FieldSpec
|
||||||
func (p *ReplicaCountTransformerPlugin) createMatcher(i int) resmap.IdMatcher {
|
func (p *ReplicaCountTransformerPlugin) createMatcher(fs types.FieldSpec) resmap.IdMatcher {
|
||||||
return func(r resid.ResId) bool {
|
return func(r resid.ResId) bool {
|
||||||
return r.Name == p.Replica.Name &&
|
return r.Name == p.Replica.Name && r.Gvk.IsSelected(&fs.Gvk)
|
||||||
r.Gvk.IsSelected(&p.FieldSpecs[i].Gvk)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ReplicaCountTransformerPlugin) addReplicas(in interface{}) (interface{}, error) {
|
|
||||||
switch m := in.(type) {
|
|
||||||
case int64:
|
|
||||||
// Was already in the field.
|
|
||||||
case map[string]interface{}:
|
|
||||||
if len(m) != 0 {
|
|
||||||
// A map was already in the replicas field, don't want to
|
|
||||||
// discard this data silently.
|
|
||||||
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
|
|
||||||
}
|
|
||||||
// Just got added, default type is map, but we can return anything.
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
|
|
||||||
}
|
|
||||||
return p.Replica.Count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin {
|
func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin {
|
||||||
return &ReplicaCountTransformerPlugin{}
|
return &ReplicaCountTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ import (
|
|||||||
type SecretGeneratorPlugin struct {
|
type SecretGeneratorPlugin struct {
|
||||||
h *resmap.PluginHelpers
|
h *resmap.PluginHelpers
|
||||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
types.GeneratorOptions
|
|
||||||
types.SecretArgs
|
types.SecretArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
|
func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
|
||||||
p.GeneratorOptions = types.GeneratorOptions{}
|
|
||||||
p.SecretArgs = types.SecretArgs{}
|
p.SecretArgs = types.SecretArgs{}
|
||||||
err = yaml.Unmarshal(config, p)
|
err = yaml.Unmarshal(config, p)
|
||||||
if p.SecretArgs.Name == "" {
|
if p.SecretArgs.Name == "" {
|
||||||
@@ -33,8 +31,7 @@ func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (
|
|||||||
|
|
||||||
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
|
||||||
return p.h.ResmapFactory().FromSecretArgs(
|
return p.h.ResmapFactory().FromSecretArgs(
|
||||||
kv.NewLoader(p.h.Loader(), p.h.Validator()),
|
kv.NewLoader(p.h.Loader(), p.h.Validator()), p.SecretArgs)
|
||||||
&p.GeneratorOptions, p.SecretArgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSecretGeneratorPlugin() resmap.GeneratorPlugin {
|
func NewSecretGeneratorPlugin() resmap.GeneratorPlugin {
|
||||||
|
|||||||
141
api/builtins/ValueAddTransformer.go
Normal file
141
api/builtins/ValueAddTransformer.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// Code generated by pluginator on ValueAddTransformer; DO NOT EDIT.
|
||||||
|
// pluginator {unknown 1970-01-01T00:00:00Z }
|
||||||
|
|
||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/namespace"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/valueadd"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An 'Add' transformer inspired by the IETF RFC 6902 JSON spec Add operation.
|
||||||
|
type ValueAddTransformerPlugin struct {
|
||||||
|
// Value is the value to add.
|
||||||
|
// Defaults to base name of encompassing kustomization root.
|
||||||
|
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||||
|
|
||||||
|
// Targets is a slice of targets that should have the value added.
|
||||||
|
Targets []Target `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||||
|
|
||||||
|
// TargetFilePath is a file path. If specified, the file will be parsed into
|
||||||
|
// a slice of Target, and appended to anything that was specified in the
|
||||||
|
// Targets field. This is just a means to share common target specifications.
|
||||||
|
TargetFilePath string `json:"targetFilePath,omitempty" yaml:"targetFilePath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target describes where to put the value.
|
||||||
|
type Target struct {
|
||||||
|
// Selector selects the resources to modify.
|
||||||
|
Selector *types.Selector `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||||
|
|
||||||
|
// NotSelector selects the resources to exclude
|
||||||
|
// from those included by overly broad selectors.
|
||||||
|
// TODO: implement this?
|
||||||
|
// NotSelector *types.Selector `json:"notSelector,omitempty" yaml:"notSelector,omitempty"`
|
||||||
|
|
||||||
|
// FieldPath is a JSON-style path to the field intended to hold the value.
|
||||||
|
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
||||||
|
|
||||||
|
// FilePathPosition is passed to the filter directly. Look there for doc.
|
||||||
|
FilePathPosition int `json:"filePathPosition,omitempty" yaml:"filePathPosition,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ValueAddTransformerPlugin) Config(h *resmap.PluginHelpers, c []byte) error {
|
||||||
|
err := yaml.Unmarshal(c, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Value = strings.TrimSpace(p.Value)
|
||||||
|
if p.Value == "" {
|
||||||
|
p.Value = filepath.Base(h.Loader().Root())
|
||||||
|
}
|
||||||
|
if p.TargetFilePath != "" {
|
||||||
|
bytes, err := h.Loader().Load(p.TargetFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var targets struct {
|
||||||
|
Targets []Target `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||||
|
}
|
||||||
|
err = yaml.Unmarshal(bytes, &targets)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Targets = append(p.Targets, targets.Targets...)
|
||||||
|
}
|
||||||
|
if len(p.Targets) == 0 {
|
||||||
|
return fmt.Errorf("must specify at least one target")
|
||||||
|
}
|
||||||
|
for _, target := range p.Targets {
|
||||||
|
if err = validateSelector(target.Selector); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: call validateSelector(target.NotSelector) if field added.
|
||||||
|
if err = validateJsonFieldPath(target.FieldPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if target.FilePathPosition < 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"value of FilePathPosition (%d) cannot be negative",
|
||||||
|
target.FilePathPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement
|
||||||
|
func validateSelector(_ *types.Selector) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Enforce RFC 6902?
|
||||||
|
func validateJsonFieldPath(p string) error {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return fmt.Errorf("fieldPath cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ValueAddTransformerPlugin) Transform(m resmap.ResMap) (err error) {
|
||||||
|
for _, t := range p.Targets {
|
||||||
|
var resources []*resource.Resource
|
||||||
|
if t.Selector == nil {
|
||||||
|
resources = m.Resources()
|
||||||
|
} else {
|
||||||
|
resources, err = m.Select(*t.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: consider t.NotSelector if implemented
|
||||||
|
for _, res := range resources {
|
||||||
|
if t.FieldPath == types.MetadataNamespacePath {
|
||||||
|
err = res.ApplyFilter(namespace.Filter{
|
||||||
|
Namespace: p.Value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
err = res.ApplyFilter(valueadd.Filter{
|
||||||
|
Value: p.Value,
|
||||||
|
FieldPath: t.FieldPath,
|
||||||
|
FilePathPosition: t.FilePathPosition,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValueAddTransformerPlugin() resmap.TransformerPlugin {
|
||||||
|
return &ValueAddTransformerPlugin{}
|
||||||
|
}
|
||||||
61
api/filesys/filesys.go
Normal file
61
api/filesys/filesys.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package filesys provides a file system abstraction,
|
||||||
|
// a subset of that provided by golang.org/pkg/os,
|
||||||
|
// with an on-disk and in-memory representation.
|
||||||
|
//
|
||||||
|
// Deprecated: use sigs.k8s.io/kustomize/kyaml/filesys instead.
|
||||||
|
package filesys
|
||||||
|
|
||||||
|
import "sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Separator is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.Separator.
|
||||||
|
Separator = filesys.Separator
|
||||||
|
// SelfDir is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.SelfDir.
|
||||||
|
SelfDir = filesys.SelfDir
|
||||||
|
// ParentDir is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.ParentDir.
|
||||||
|
ParentDir = filesys.ParentDir
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// FileSystem is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.FileSystem.
|
||||||
|
FileSystem = filesys.FileSystem
|
||||||
|
// FileSystemOrOnDisk is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.FileSystemOrOnDisk.
|
||||||
|
FileSystemOrOnDisk = filesys.FileSystemOrOnDisk
|
||||||
|
// ConfirmedDir is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.ConfirmedDir.
|
||||||
|
ConfirmedDir = filesys.ConfirmedDir
|
||||||
|
)
|
||||||
|
|
||||||
|
// MakeEmptyDirInMemory is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.MakeEmptyDirInMemory.
|
||||||
|
func MakeEmptyDirInMemory() FileSystem { return filesys.MakeEmptyDirInMemory() }
|
||||||
|
|
||||||
|
// MakeFsInMemory is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.MakeFsInMemory.
|
||||||
|
func MakeFsInMemory() FileSystem { return filesys.MakeFsInMemory() }
|
||||||
|
|
||||||
|
// MakeFsOnDisk is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.MakeFsOnDisk.
|
||||||
|
func MakeFsOnDisk() FileSystem { return filesys.MakeFsOnDisk() }
|
||||||
|
|
||||||
|
// NewTmpConfirmedDir is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.NewTmpConfirmedDir.
|
||||||
|
func NewTmpConfirmedDir() (filesys.ConfirmedDir, error) { return filesys.NewTmpConfirmedDir() }
|
||||||
|
|
||||||
|
// RootedPath is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.RootedPath.
|
||||||
|
func RootedPath(elem ...string) string { return filesys.RootedPath(elem...) }
|
||||||
|
|
||||||
|
// StripTrailingSeps is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.StripTrailingSeps.
|
||||||
|
func StripTrailingSeps(s string) string { return filesys.StripTrailingSeps(s) }
|
||||||
|
|
||||||
|
// StripLeadingSeps is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.StripLeadingSeps.
|
||||||
|
func StripLeadingSeps(s string) string { return filesys.StripLeadingSeps(s) }
|
||||||
|
|
||||||
|
// PathSplit is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.PathSplit.
|
||||||
|
func PathSplit(incoming string) []string { return filesys.PathSplit(incoming) }
|
||||||
|
|
||||||
|
// PathJoin is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.PathJoin.
|
||||||
|
func PathJoin(incoming []string) string { return filesys.PathJoin(incoming) }
|
||||||
|
|
||||||
|
// InsertPathPart is deprecated, use sigs.k8s.io/kustomize/kyaml/filesys.InsertPathPart.
|
||||||
|
func InsertPathPart(path string, pos int, part string) string {
|
||||||
|
return filesys.InsertPathPart(path, pos, part)
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Package filesys provides a file system abstraction layer.
|
|
||||||
package filesys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Separator = string(filepath.Separator)
|
|
||||||
SelfDir = "."
|
|
||||||
ParentDir = ".."
|
|
||||||
)
|
|
||||||
|
|
||||||
// FileSystem groups basic os filesystem methods.
|
|
||||||
// It's supposed be functional subset of https://golang.org/pkg/os
|
|
||||||
type FileSystem interface {
|
|
||||||
// Create a file.
|
|
||||||
Create(path string) (File, error)
|
|
||||||
// MkDir makes a directory.
|
|
||||||
Mkdir(path string) error
|
|
||||||
// MkDirAll makes a directory path, creating intervening directories.
|
|
||||||
MkdirAll(path string) error
|
|
||||||
// RemoveAll removes path and any children it contains.
|
|
||||||
RemoveAll(path string) error
|
|
||||||
// Open opens the named file for reading.
|
|
||||||
Open(path string) (File, error)
|
|
||||||
// IsDir returns true if the path is a directory.
|
|
||||||
IsDir(path string) bool
|
|
||||||
// CleanedAbs converts the given path into a
|
|
||||||
// directory and a file name, where the directory
|
|
||||||
// is represented as a ConfirmedDir and all that implies.
|
|
||||||
// If the entire path is a directory, the file component
|
|
||||||
// is an empty string.
|
|
||||||
CleanedAbs(path string) (ConfirmedDir, string, error)
|
|
||||||
// Exists is true if the path exists in the file system.
|
|
||||||
Exists(path string) bool
|
|
||||||
// Glob returns the list of matching files,
|
|
||||||
// emulating https://golang.org/pkg/path/filepath/#Glob
|
|
||||||
Glob(pattern string) ([]string, error)
|
|
||||||
// ReadFile returns the contents of the file at the given path.
|
|
||||||
ReadFile(path string) ([]byte, error)
|
|
||||||
// WriteFile writes the data to a file at the given path,
|
|
||||||
// overwriting anything that's already there.
|
|
||||||
WriteFile(path string, data []byte) error
|
|
||||||
// Walk walks the file system with the given WalkFunc.
|
|
||||||
Walk(path string, walkFn filepath.WalkFunc) error
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package filesys_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "sigs.k8s.io/kustomize/api/filesys"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeTestDir(t *testing.T) (FileSystem, string) {
|
|
||||||
fSys := MakeFsOnDisk()
|
|
||||||
td, err := ioutil.TempDir("", "kustomize_testing_dir")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error %s", err)
|
|
||||||
}
|
|
||||||
testDir, err := filepath.EvalSymlinks(td)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error %s", err)
|
|
||||||
}
|
|
||||||
if !fSys.Exists(testDir) {
|
|
||||||
t.Fatalf("expected existence")
|
|
||||||
}
|
|
||||||
if !fSys.IsDir(testDir) {
|
|
||||||
t.Fatalf("expected directory")
|
|
||||||
}
|
|
||||||
return fSys, testDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCleanedAbs_1(t *testing.T) {
|
|
||||||
fSys, testDir := makeTestDir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
d, f, err := fSys.CleanedAbs("")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
if d.String() != wd {
|
|
||||||
t.Fatalf("unexpected d=%s", d)
|
|
||||||
}
|
|
||||||
if f != "" {
|
|
||||||
t.Fatalf("unexpected f=%s", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCleanedAbs_2(t *testing.T) {
|
|
||||||
fSys, testDir := makeTestDir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
d, f, err := fSys.CleanedAbs("/")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
if d != "/" {
|
|
||||||
t.Fatalf("unexpected d=%s", d)
|
|
||||||
}
|
|
||||||
if f != "" {
|
|
||||||
t.Fatalf("unexpected f=%s", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCleanedAbs_3(t *testing.T) {
|
|
||||||
fSys, testDir := makeTestDir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
err := fSys.WriteFile(
|
|
||||||
filepath.Join(testDir, "foo"), []byte(`foo`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
d, f, err := fSys.CleanedAbs(filepath.Join(testDir, "foo"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
if d.String() != testDir {
|
|
||||||
t.Fatalf("unexpected d=%s", d)
|
|
||||||
}
|
|
||||||
if f != "foo" {
|
|
||||||
t.Fatalf("unexpected f=%s", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCleanedAbs_4(t *testing.T) {
|
|
||||||
fSys, testDir := makeTestDir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
err := fSys.MkdirAll(filepath.Join(testDir, "d1", "d2"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
err = fSys.WriteFile(
|
|
||||||
filepath.Join(testDir, "d1", "d2", "bar"),
|
|
||||||
[]byte(`bar`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
d, f, err := fSys.CleanedAbs(
|
|
||||||
filepath.Join(testDir, "d1", "d2"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
if d.String() != filepath.Join(testDir, "d1", "d2") {
|
|
||||||
t.Fatalf("unexpected d=%s", d)
|
|
||||||
}
|
|
||||||
if f != "" {
|
|
||||||
t.Fatalf("unexpected f=%s", f)
|
|
||||||
}
|
|
||||||
|
|
||||||
d, f, err = fSys.CleanedAbs(
|
|
||||||
filepath.Join(testDir, "d1", "d2", "bar"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err=%v", err)
|
|
||||||
}
|
|
||||||
if d.String() != filepath.Join(testDir, "d1", "d2") {
|
|
||||||
t.Fatalf("unexpected d=%s", d)
|
|
||||||
}
|
|
||||||
if f != "bar" {
|
|
||||||
t.Fatalf("unexpected f=%s", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReadFilesRealFS(t *testing.T) {
|
|
||||||
fSys, testDir := makeTestDir(t)
|
|
||||||
defer os.RemoveAll(testDir)
|
|
||||||
|
|
||||||
err := fSys.WriteFile(path.Join(testDir, "foo"), []byte(`foo`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error %s", err)
|
|
||||||
}
|
|
||||||
if !fSys.Exists(path.Join(testDir, "foo")) {
|
|
||||||
t.Fatalf("expected foo")
|
|
||||||
}
|
|
||||||
if fSys.IsDir(path.Join(testDir, "foo")) {
|
|
||||||
t.Fatalf("expected foo not to be a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = fSys.WriteFile(path.Join(testDir, "bar"), []byte(`bar`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := fSys.Glob(path.Join("testDir", "*"))
|
|
||||||
expected := []string{
|
|
||||||
path.Join(testDir, "bar"),
|
|
||||||
path.Join(testDir, "foo"),
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error")
|
|
||||||
}
|
|
||||||
if reflect.DeepEqual(files, expected) {
|
|
||||||
t.Fatalf("incorrect files found by glob: %v", files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package filesys
|
|
||||||
|
|
||||||
import "path/filepath"
|
|
||||||
|
|
||||||
// RootedPath returns a rooted path, e.g. "/foo/bar" as
|
|
||||||
// opposed to "foo/bar".
|
|
||||||
func RootedPath(elem ...string) string {
|
|
||||||
return Separator + filepath.Join(elem...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StripTrailingSeps trims trailing filepath separators from input.
|
|
||||||
func StripTrailingSeps(s string) string {
|
|
||||||
k := len(s)
|
|
||||||
for k > 0 && s[k-1] == filepath.Separator {
|
|
||||||
k--
|
|
||||||
}
|
|
||||||
return s[:k]
|
|
||||||
}
|
|
||||||
|
|
||||||
// StripLeadingSeps trims leading filepath separators from input.
|
|
||||||
func StripLeadingSeps(s string) string {
|
|
||||||
k := 0
|
|
||||||
for k < len(s) && s[k] == filepath.Separator {
|
|
||||||
k++
|
|
||||||
}
|
|
||||||
return s[k:]
|
|
||||||
}
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
package filesys_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "sigs.k8s.io/kustomize/api/filesys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Confirm behavior of filepath.Match
|
|
||||||
func TestFilePathMatch(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
pattern string
|
|
||||||
path string
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
pattern: "*e*",
|
|
||||||
path: "hey",
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*e*",
|
|
||||||
path: "hay",
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*e*",
|
|
||||||
path: filepath.Join("h", "e", "y"),
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*/e/*",
|
|
||||||
path: filepath.Join("h", "e", "y"),
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "h/e/*",
|
|
||||||
path: filepath.Join("h", "e", "y"),
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*/e/y",
|
|
||||||
path: filepath.Join("h", "e", "y"),
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*/*/*",
|
|
||||||
path: filepath.Join("h", "e", "y"),
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*/*/*",
|
|
||||||
path: filepath.Join("h", "e", "y", "there"),
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "*/*/*/t*e",
|
|
||||||
path: filepath.Join("h", "e", "y", "there"),
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, item := range cases {
|
|
||||||
match, err := filepath.Match(item.pattern, item.path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
if match != item.expected {
|
|
||||||
t.Fatalf("'%s' '%s' %v\n", item.pattern, item.path, match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm behavior of filepath.Split
|
|
||||||
func TestFilePathSplit(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
full string
|
|
||||||
dir string
|
|
||||||
file string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
full: "",
|
|
||||||
dir: "",
|
|
||||||
file: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: SelfDir,
|
|
||||||
dir: "",
|
|
||||||
file: SelfDir,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "rabbit.jpg",
|
|
||||||
dir: "",
|
|
||||||
file: "rabbit.jpg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/beans",
|
|
||||||
dir: "/",
|
|
||||||
file: "beans",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/home/foo/bar",
|
|
||||||
dir: "/home/foo/",
|
|
||||||
file: "bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/usr/local/",
|
|
||||||
dir: "/usr/local/",
|
|
||||||
file: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/usr//local//go",
|
|
||||||
dir: "/usr//local//",
|
|
||||||
file: "go",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, p := range cases {
|
|
||||||
dir, file := filepath.Split(p.full)
|
|
||||||
if dir != p.dir || file != p.file {
|
|
||||||
t.Fatalf(
|
|
||||||
"in '%s',\ngot dir='%s' (expected '%s'),\n got file='%s' (expected %s).",
|
|
||||||
p.full, dir, p.dir, file, p.file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStripTrailingSeps(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
full string
|
|
||||||
rem string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
full: "foo",
|
|
||||||
rem: "foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "foo/",
|
|
||||||
rem: "foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "foo///bar///",
|
|
||||||
rem: "foo///bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/////",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, p := range cases {
|
|
||||||
dir := StripTrailingSeps(p.full)
|
|
||||||
if dir != p.rem {
|
|
||||||
t.Fatalf(
|
|
||||||
"in '%s', got dir='%s' (expected '%s')",
|
|
||||||
p.full, dir, p.rem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStripLeadingSeps(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
full string
|
|
||||||
rem string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
full: "foo",
|
|
||||||
rem: "foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/foo",
|
|
||||||
rem: "foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "///foo///bar///",
|
|
||||||
rem: "foo///bar///",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/////",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
full: "/",
|
|
||||||
rem: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, p := range cases {
|
|
||||||
dir := StripLeadingSeps(p.full)
|
|
||||||
if dir != p.rem {
|
|
||||||
t.Fatalf(
|
|
||||||
"in '%s', got dir='%s' (expected '%s')",
|
|
||||||
p.full, dir, p.rem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,14 +24,16 @@ type Filter struct {
|
|||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
keys := filtersutil.SortedMapKeys(f.Annotations)
|
keys := yaml.SortedMapKeys(f.Annotations)
|
||||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||||
func(node *yaml.RNode) (*yaml.RNode, error) {
|
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if err := node.PipeE(fsslice.Filter{
|
if err := node.PipeE(fsslice.Filter{
|
||||||
FsSlice: f.FsSlice,
|
FsSlice: f.FsSlice,
|
||||||
SetValue: fsslice.SetEntry(k, f.Annotations[k]),
|
SetValue: filtersutil.SetEntry(
|
||||||
|
k, f.Annotations[k], yaml.NodeTagString),
|
||||||
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
|
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
|
||||||
|
CreateTag: yaml.NodeTagMap,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,93 @@ a:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"number": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
2: ford
|
||||||
|
clown: "1"
|
||||||
|
`,
|
||||||
|
filter: Filter{Annotations: annoMap{
|
||||||
|
"clown": "1",
|
||||||
|
"2": "ford",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// test quoting of values which are not considered strings in yaml 1.1
|
||||||
|
"yaml_1_1_compatibility": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
a: "y"
|
||||||
|
b: y1
|
||||||
|
c: "yes"
|
||||||
|
d: yes1
|
||||||
|
e: "true"
|
||||||
|
f: true1
|
||||||
|
`,
|
||||||
|
filter: Filter{Annotations: annoMap{
|
||||||
|
"a": "y",
|
||||||
|
"b": "y1",
|
||||||
|
"c": "yes",
|
||||||
|
"d": "yes1",
|
||||||
|
"e": "true",
|
||||||
|
"f": "true1",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// test quoting of values which are not considered strings in yaml 1.1
|
||||||
|
"null_annotations": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations: null
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
annotations:
|
||||||
|
a: a1
|
||||||
|
b: b1
|
||||||
|
`,
|
||||||
|
filter: Filter{Annotations: annoMap{
|
||||||
|
"a": "a1",
|
||||||
|
"b": "b1",
|
||||||
|
}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ metadata:
|
|||||||
`)}},
|
`)}},
|
||||||
Filters: []kio.Filter{Filter{
|
Filters: []kio.Filter{Filter{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
|
"booleanValue": "true",
|
||||||
|
"numberValue": "42",
|
||||||
},
|
},
|
||||||
FsSlice: fss,
|
FsSlice: fss,
|
||||||
}},
|
}},
|
||||||
@@ -44,12 +46,16 @@ metadata:
|
|||||||
// metadata:
|
// metadata:
|
||||||
// name: instance
|
// name: instance
|
||||||
// annotations:
|
// annotations:
|
||||||
|
// booleanValue: "true"
|
||||||
// foo: bar
|
// foo: bar
|
||||||
|
// numberValue: "42"
|
||||||
// ---
|
// ---
|
||||||
// apiVersion: example.com/v1
|
// apiVersion: example.com/v1
|
||||||
// kind: Bar
|
// kind: Bar
|
||||||
// metadata:
|
// metadata:
|
||||||
// name: instance
|
// name: instance
|
||||||
// annotations:
|
// annotations:
|
||||||
|
// booleanValue: "true"
|
||||||
// foo: bar
|
// foo: bar
|
||||||
|
// numberValue: "42"
|
||||||
}
|
}
|
||||||
|
|||||||
5
api/filters/doc.go
Normal file
5
api/filters/doc.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package filters
|
||||||
|
|
||||||
|
// Package filters collects various implementations
|
||||||
|
// sigs.k8s.io/kustomize/kyaml/kio.Filter used by kustomize
|
||||||
|
// transformers to modify kubernetes objects.
|
||||||
6
api/filters/fieldspec/doc.go
Normal file
6
api/filters/fieldspec/doc.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package fieldspec contains a yaml.Filter to modify a resource
|
||||||
|
// that matches the FieldSpec.
|
||||||
|
package fieldspec
|
||||||
61
api/filters/fieldspec/example_test.go
Normal file
61
api/filters/fieldspec/example_test.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package fieldspec_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
in := &kio.ByteReader{
|
||||||
|
Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`),
|
||||||
|
}
|
||||||
|
fltr := Filter{
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
SetValue: filtersutil.SetScalar("green"),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "a/b", CreateIfNotPresent: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{in},
|
||||||
|
Filters: []kio.Filter{kio.FilterAll(fltr)},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// a:
|
||||||
|
// b: green
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Bar
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// a:
|
||||||
|
// b: green
|
||||||
|
}
|
||||||
181
api/filters/fieldspec/fieldspec.go
Normal file
181
api/filters/fieldspec/fieldspec.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package fieldspec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ yaml.Filter = Filter{}
|
||||||
|
|
||||||
|
// Filter possibly mutates its object argument using a FieldSpec.
|
||||||
|
// If the object matches the FieldSpec, and the node found
|
||||||
|
// by following the fieldSpec's path is non-null, this filter calls
|
||||||
|
// the setValue function on the node at the end of the path.
|
||||||
|
// If any part of the path doesn't exist, the filter returns
|
||||||
|
// without doing anything and without error, unless it was set
|
||||||
|
// to create the path. If set to create, it creates a tree of maps
|
||||||
|
// along the path, and the leaf node gets the setValue called on it.
|
||||||
|
// Error on GVK mismatch, empty or poorly formed path.
|
||||||
|
// Filter expect kustomize style paths, not JSON paths.
|
||||||
|
// Filter stores internal state and should not be reused
|
||||||
|
type Filter struct {
|
||||||
|
// FieldSpec contains the path to the value to set.
|
||||||
|
FieldSpec types.FieldSpec `yaml:"fieldSpec"`
|
||||||
|
|
||||||
|
// Set the field using this function
|
||||||
|
SetValue filtersutil.SetFn
|
||||||
|
|
||||||
|
// CreateKind defines the type of node to create if the field is not found
|
||||||
|
CreateKind yaml.Kind
|
||||||
|
|
||||||
|
CreateTag string
|
||||||
|
|
||||||
|
// path keeps internal state about the current path
|
||||||
|
path []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
// check if the FieldSpec applies to the object
|
||||||
|
if match := isMatchGVK(fltr.FieldSpec, obj); !match {
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
fltr.path = utils.PathSplitter(fltr.FieldSpec.Path, "/")
|
||||||
|
if err := fltr.filter(obj); err != nil {
|
||||||
|
s, _ := obj.String()
|
||||||
|
return nil, errors.WrapPrefixf(err,
|
||||||
|
"considering field '%s' of object\n%v", fltr.FieldSpec.Path, s)
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively called.
|
||||||
|
func (fltr Filter) filter(obj *yaml.RNode) error {
|
||||||
|
if len(fltr.path) == 0 {
|
||||||
|
// found the field -- set its value
|
||||||
|
return fltr.SetValue(obj)
|
||||||
|
}
|
||||||
|
if obj.IsTaggedNull() || obj.IsNil() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch obj.YNode().Kind {
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return fltr.handleSequence(obj)
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return fltr.handleMap(obj)
|
||||||
|
case yaml.AliasNode:
|
||||||
|
return fltr.filter(yaml.NewRNode(obj.YNode().Alias))
|
||||||
|
default:
|
||||||
|
return errors.Errorf("expected sequence or mapping node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMap calls filter on the map field matching the next path element
|
||||||
|
func (fltr Filter) handleMap(obj *yaml.RNode) error {
|
||||||
|
fieldName, isSeq := isSequenceField(fltr.path[0])
|
||||||
|
if fieldName == "" {
|
||||||
|
return fmt.Errorf("cannot set or create an empty field name")
|
||||||
|
}
|
||||||
|
// lookup the field matching the next path element
|
||||||
|
var operation yaml.Filter
|
||||||
|
var kind yaml.Kind
|
||||||
|
tag := yaml.NodeTagEmpty
|
||||||
|
switch {
|
||||||
|
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
|
||||||
|
// don't create the field if we don't find it
|
||||||
|
operation = yaml.Lookup(fieldName)
|
||||||
|
if isSeq {
|
||||||
|
// The query path thinks this field should be a sequence;
|
||||||
|
// accept this hint for use later if the tag is NodeTagNull.
|
||||||
|
kind = yaml.SequenceNode
|
||||||
|
}
|
||||||
|
case len(fltr.path) <= 1:
|
||||||
|
// create the field if it is missing: use the provided node kind
|
||||||
|
operation = yaml.LookupCreate(fltr.CreateKind, fieldName)
|
||||||
|
kind = fltr.CreateKind
|
||||||
|
tag = fltr.CreateTag
|
||||||
|
default:
|
||||||
|
// create the field if it is missing: must be a mapping node
|
||||||
|
operation = yaml.LookupCreate(yaml.MappingNode, fieldName)
|
||||||
|
kind = yaml.MappingNode
|
||||||
|
tag = yaml.NodeTagMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate (or maybe create) the field
|
||||||
|
field, err := obj.Pipe(operation)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
|
||||||
|
}
|
||||||
|
if field == nil {
|
||||||
|
// No error if field not found.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the value exists, but is null and kind is set,
|
||||||
|
// then change it to the creation type
|
||||||
|
// TODO: update yaml.LookupCreate to support this
|
||||||
|
if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
|
||||||
|
field.YNode().Kind = kind
|
||||||
|
field.YNode().Tag = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the current fltr and change the path on the copy
|
||||||
|
var next = fltr
|
||||||
|
// call filter for the next path element on the matching field
|
||||||
|
next.path = fltr.path[1:]
|
||||||
|
return next.filter(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
// seq calls filter on all sequence elements
|
||||||
|
func (fltr Filter) handleSequence(obj *yaml.RNode) error {
|
||||||
|
if err := obj.VisitElements(func(node *yaml.RNode) error {
|
||||||
|
// recurse on each element -- re-allocating a Filter is
|
||||||
|
// not strictly required, but is more consistent with field
|
||||||
|
// and less likely to have side effects
|
||||||
|
// keep the entire path -- it does not contain parts for sequences
|
||||||
|
return fltr.filter(node)
|
||||||
|
}); err != nil {
|
||||||
|
return errors.WrapPrefixf(err,
|
||||||
|
"visit traversal on path: %v", fltr.path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isSequenceField returns true if the path element is for a sequence field.
|
||||||
|
// isSequence also returns the path element with the '[]' suffix trimmed
|
||||||
|
func isSequenceField(name string) (string, bool) {
|
||||||
|
shorter := strings.TrimSuffix(name, "[]")
|
||||||
|
return shorter, shorter != name
|
||||||
|
}
|
||||||
|
|
||||||
|
// isMatchGVK returns true if the fs.GVK matches the obj GVK.
|
||||||
|
func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) bool {
|
||||||
|
if kind := obj.GetKind(); fs.Kind != "" && fs.Kind != kind {
|
||||||
|
// kind doesn't match
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the group and version from the apiVersion field
|
||||||
|
group, version := resid.ParseGroupVersion(obj.GetApiVersion())
|
||||||
|
|
||||||
|
if fs.Group != "" && fs.Group != group {
|
||||||
|
// group doesn't match
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if fs.Version != "" && fs.Version != version {
|
||||||
|
// version doesn't match
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
568
api/filters/fieldspec/fieldspec_test.go
Normal file
568
api/filters/fieldspec/fieldspec_test.go
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package fieldspec_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter_Filter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
filter fieldspec.Filter
|
||||||
|
fieldSpec string
|
||||||
|
error string
|
||||||
|
}{
|
||||||
|
"path not found": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo
|
||||||
|
kind: Bar
|
||||||
|
xxx:
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo
|
||||||
|
kind: Bar
|
||||||
|
xxx:
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"empty path": {
|
||||||
|
fieldSpec: `
|
||||||
|
group: foo
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1
|
||||||
|
kind: Bar
|
||||||
|
xxx:
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo
|
||||||
|
kind: Bar
|
||||||
|
xxx:
|
||||||
|
`,
|
||||||
|
error: `considering field '' of object
|
||||||
|
apiVersion: foo/v1
|
||||||
|
kind: Bar
|
||||||
|
xxx:
|
||||||
|
: cannot set or create an empty field name`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"update": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: e
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"update-kind-not-match": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
kind: Bar1
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar2
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar2
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"update-group-not-match": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo2/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo2/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"update-version-not-match": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
version: v1beta1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta2
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta2
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"bad-version": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
version: v1beta1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta2/something
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta2/something
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"bad-meta": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: foo
|
||||||
|
version: v1beta1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
a:
|
||||||
|
b: c
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"miss-match-type": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b/c
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: a
|
||||||
|
`,
|
||||||
|
error: `considering field 'a/b/c' of object
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: a
|
||||||
|
: expected sequence or mapping node`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"add": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b/c/d
|
||||||
|
group: foo
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a: {}
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a: {b: {c: {d: e}}}
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"update-in-sequence": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b[]/c/d
|
||||||
|
group: foo
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
- c:
|
||||||
|
d: a
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
- c:
|
||||||
|
d: e
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Don't create a sequence
|
||||||
|
"empty-sequence-no-create": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b[]/c/d
|
||||||
|
group: foo
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a: {}
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a: {}
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create a new field for an element in a sequence
|
||||||
|
"empty-sequence-create": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b[]/c/d
|
||||||
|
group: foo
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
- c: {}
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1beta1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
- c: {d: e}
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"group v1": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
group: v1
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"version v1": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b
|
||||||
|
version: v1
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b: e
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"successfully set field on array entry no sequence hint": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: spec/containers/image
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: foo
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: bar
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"successfully set field on array entry with sequence hint": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: spec/containers[]/image
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: foo
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: bar
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"failure to set field on array entry with sequence hint in path": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: spec/containers[]/image
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers: []
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"failure to set field on array entry, no sequence hint in path": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: spec/containers/image
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"fieldname with slash '/'": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b\/c/d
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b/c:
|
||||||
|
d: foo
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b/c:
|
||||||
|
d: bar
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"fieldname with multiple '/'": {
|
||||||
|
fieldSpec: `
|
||||||
|
path: a/b\/c/d\/e/f
|
||||||
|
version: v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b/c:
|
||||||
|
d/e:
|
||||||
|
f: foo
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Bar
|
||||||
|
a:
|
||||||
|
b/c:
|
||||||
|
d/e:
|
||||||
|
f: bar
|
||||||
|
`,
|
||||||
|
filter: fieldspec.Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("bar"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := range testCases {
|
||||||
|
tc := testCases[n]
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
err := yaml.Unmarshal([]byte(tc.fieldSpec), &tc.filter.FieldSpec)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
rw := &kio.ByteReadWriter{
|
||||||
|
Reader: bytes.NewBufferString(tc.input),
|
||||||
|
Writer: out,
|
||||||
|
OmitReaderAnnotations: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the filter
|
||||||
|
err = kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{rw},
|
||||||
|
Filters: []kio.Filter{kio.FilterAll(tc.filter)},
|
||||||
|
Outputs: []kio.Writer{rw},
|
||||||
|
}.Execute()
|
||||||
|
if tc.error != "" {
|
||||||
|
if !assert.EqualError(t, err, tc.error) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
// stop rest of test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// check results
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expected),
|
||||||
|
strings.TrimSpace(out.String())) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package filtersutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SortedMapKeys returns a sorted slice of keys to the given map.
|
|
||||||
// Writing this function never gets old.
|
|
||||||
func SortedMapKeys(m map[string]string) []string {
|
|
||||||
keys := make([]string, len(m))
|
|
||||||
i := 0
|
|
||||||
for k := range m {
|
|
||||||
keys[i] = k
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package filtersutil_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSortedKeys(t *testing.T) {
|
|
||||||
testCases := map[string]struct {
|
|
||||||
input map[string]string
|
|
||||||
expected []string
|
|
||||||
}{
|
|
||||||
"empty": {
|
|
||||||
input: map[string]string{},
|
|
||||||
expected: []string{}},
|
|
||||||
"one": {
|
|
||||||
input: map[string]string{"a": "aaa"},
|
|
||||||
expected: []string{"a"}},
|
|
||||||
"three": {
|
|
||||||
input: map[string]string{"c": "ccc", "b": "bbb", "a": "aaa"},
|
|
||||||
expected: []string{"a", "b", "c"}},
|
|
||||||
}
|
|
||||||
for tn, tc := range testCases {
|
|
||||||
t.Run(tn, func(t *testing.T) {
|
|
||||||
if !assert.Equal(t,
|
|
||||||
filtersutil.SortedMapKeys(tc.input),
|
|
||||||
tc.expected) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
api/filters/filtersutil/setters.go
Normal file
33
api/filters/filtersutil/setters.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package filtersutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetFn is a function that accepts an RNode to possibly modify.
|
||||||
|
type SetFn func(*yaml.RNode) error
|
||||||
|
|
||||||
|
// SetScalar returns a SetFn to set a scalar value
|
||||||
|
func SetScalar(value string) SetFn {
|
||||||
|
return func(node *yaml.RNode) error {
|
||||||
|
return node.PipeE(yaml.FieldSetter{StringValue: value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEntry returns a SetFn to set an entry in a map
|
||||||
|
func SetEntry(key, value, tag string) SetFn {
|
||||||
|
n := &yaml.Node{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: value,
|
||||||
|
Tag: tag,
|
||||||
|
}
|
||||||
|
if tag == yaml.NodeTagString && yaml.IsYaml1_1NonString(n) {
|
||||||
|
n.Style = yaml.DoubleQuotedStyle
|
||||||
|
}
|
||||||
|
return func(node *yaml.RNode) error {
|
||||||
|
return node.PipeE(yaml.FieldSetter{
|
||||||
|
Name: key,
|
||||||
|
Value: yaml.NewRNode(n),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Copyright 2020 The Kubernetes Authors.
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package fsslice contains a yaml.Filter to modify a resource using an
|
// Package fsslice contains a yaml.Filter to modify a resource if
|
||||||
// FsSlice to identify fields to be updated within the resource.
|
// it matches one or more FieldSpec entries.
|
||||||
package fsslice
|
package fsslice
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
@@ -30,7 +31,7 @@ metadata:
|
|||||||
}
|
}
|
||||||
fltr := fsslice.Filter{
|
fltr := fsslice.Filter{
|
||||||
CreateKind: yaml.ScalarNode,
|
CreateKind: yaml.ScalarNode,
|
||||||
SetValue: fsslice.SetScalar("green"),
|
SetValue: filtersutil.SetScalar("green"),
|
||||||
FsSlice: []types.FieldSpec{
|
FsSlice: []types.FieldSpec{
|
||||||
{Path: "a/b", CreateIfNotPresent: true},
|
{Path: "a/b", CreateIfNotPresent: true},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fsslice
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fieldSpecFilter applies a single fieldSpec to a single object
|
|
||||||
// fieldSpecFilter stores internal state and should not be reused
|
|
||||||
type fieldSpecFilter struct {
|
|
||||||
// FieldSpec contains the path to the value to set.
|
|
||||||
FieldSpec types.FieldSpec `yaml:"fieldSpec"`
|
|
||||||
|
|
||||||
// Set the field using this function
|
|
||||||
SetValue SetFn
|
|
||||||
|
|
||||||
// CreateKind defines the type of node to create if the field is not found
|
|
||||||
CreateKind yaml.Kind
|
|
||||||
|
|
||||||
// path keeps internal state about the current path
|
|
||||||
path []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
// check if the FieldSpec applies to the object
|
|
||||||
if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil {
|
|
||||||
return obj, errors.Wrap(err)
|
|
||||||
}
|
|
||||||
fltr.path = strings.Split(fltr.FieldSpec.Path, "/")
|
|
||||||
if err := fltr.filter(obj); err != nil {
|
|
||||||
s, _ := obj.String()
|
|
||||||
return nil, errors.WrapPrefixf(err,
|
|
||||||
"obj %v at path %v", s, fltr.FieldSpec.Path)
|
|
||||||
}
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error {
|
|
||||||
if len(fltr.path) == 0 {
|
|
||||||
// found the field -- set its value
|
|
||||||
return fltr.SetValue(obj)
|
|
||||||
}
|
|
||||||
switch obj.YNode().Kind {
|
|
||||||
case yaml.SequenceNode:
|
|
||||||
return fltr.seq(obj)
|
|
||||||
case yaml.MappingNode:
|
|
||||||
return fltr.field(obj)
|
|
||||||
}
|
|
||||||
// not found -- this might be an error since the type doesn't match
|
|
||||||
|
|
||||||
return errors.Errorf("unsupported yaml node")
|
|
||||||
}
|
|
||||||
|
|
||||||
// field calls filter on the field matching the next path element
|
|
||||||
func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
|
|
||||||
fieldName, isSeq := isSequenceField(fltr.path[0])
|
|
||||||
|
|
||||||
// lookup the field matching the next path element
|
|
||||||
var lookupField yaml.Filter
|
|
||||||
switch {
|
|
||||||
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
|
|
||||||
// dont' create the field if we don't find it
|
|
||||||
lookupField = yaml.Lookup(fieldName)
|
|
||||||
case len(fltr.path) <= 1:
|
|
||||||
// create the field if it is missing: use the provided node kind
|
|
||||||
lookupField = yaml.LookupCreate(fltr.CreateKind, fieldName)
|
|
||||||
default:
|
|
||||||
// create the field if it is missing: must be a mapping node
|
|
||||||
lookupField = yaml.LookupCreate(yaml.MappingNode, fieldName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// locate (or maybe create) the field
|
|
||||||
field, err := obj.Pipe(lookupField)
|
|
||||||
if err != nil || field == nil {
|
|
||||||
return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the current fltr and change the path on the copy
|
|
||||||
var next = fltr
|
|
||||||
// call filter for the next path element on the matching field
|
|
||||||
next.path = fltr.path[1:]
|
|
||||||
return next.filter(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
// seq calls filter on all sequence elements
|
|
||||||
func (fltr fieldSpecFilter) seq(obj *yaml.RNode) error {
|
|
||||||
if err := obj.VisitElements(func(node *yaml.RNode) error {
|
|
||||||
// recurse on each element -- re-allocating a fieldSpecFilter is
|
|
||||||
// not strictly required, but is more consistent with field
|
|
||||||
// and less likely to have side effects
|
|
||||||
// keep the entire path -- it does not contain parts for sequences
|
|
||||||
return fltr.filter(node)
|
|
||||||
}); err != nil {
|
|
||||||
return errors.WrapPrefixf(err,
|
|
||||||
"visit traversal on path: %v", fltr.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSequenceField returns true if the path element is for a sequence field.
|
|
||||||
// isSequence also returns the path element with the '[]' suffix trimmed
|
|
||||||
func isSequenceField(name string) (string, bool) {
|
|
||||||
isSeq := strings.HasSuffix(name, "[]")
|
|
||||||
name = strings.TrimSuffix(name, "[]")
|
|
||||||
return name, isSeq
|
|
||||||
}
|
|
||||||
|
|
||||||
// isMatchGVK returns true if the fs.GVK matches the obj GVK.
|
|
||||||
func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) {
|
|
||||||
meta, err := obj.GetMeta()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if fs.Kind != "" && fs.Kind != meta.Kind {
|
|
||||||
// kind doesn't match
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the group and version from the apiVersion field
|
|
||||||
var group, version string
|
|
||||||
parts := strings.SplitN(meta.APIVersion, "/", 2)
|
|
||||||
group = parts[0]
|
|
||||||
if len(parts) > 1 {
|
|
||||||
version = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if fs.Group != "" && fs.Group != group {
|
|
||||||
// group doesn't match
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if fs.Version != "" && fs.Version != version {
|
|
||||||
// version doesn't match
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
@@ -4,43 +4,28 @@
|
|||||||
package fsslice
|
package fsslice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetFn sets a value
|
|
||||||
type SetFn func(*yaml.RNode) error
|
|
||||||
|
|
||||||
// SetScalar returns a SetFn to set a scalar value
|
|
||||||
func SetScalar(value string) SetFn {
|
|
||||||
return func(node *yaml.RNode) error {
|
|
||||||
return node.PipeE(yaml.FieldSetter{StringValue: value})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEntry returns a SetFn to set an entry in a map
|
|
||||||
func SetEntry(key, value string) SetFn {
|
|
||||||
return func(node *yaml.RNode) error {
|
|
||||||
return node.PipeE(yaml.FieldSetter{
|
|
||||||
Name: key, StringValue: value})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ yaml.Filter = Filter{}
|
var _ yaml.Filter = Filter{}
|
||||||
|
|
||||||
// Filter uses an FsSlice to modify fields on a single object
|
// Filter ranges over an FsSlice to modify fields on a single object.
|
||||||
|
// An FsSlice is a range of FieldSpecs. A FieldSpec is a GVK plus a path.
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
// FieldSpecList list of FieldSpecs to set
|
// FieldSpecList list of FieldSpecs to set
|
||||||
FsSlice types.FsSlice `yaml:"fsSlice"`
|
FsSlice types.FsSlice `yaml:"fsSlice"`
|
||||||
|
|
||||||
// SetValue is called on each field that matches one of the FieldSpecs
|
// SetValue is called on each field that matches one of the FieldSpecs
|
||||||
SetValue SetFn
|
SetValue filtersutil.SetFn
|
||||||
|
|
||||||
// CreateKind is used to create fields that do not exist
|
// CreateKind is used to create fields that do not exist
|
||||||
CreateKind yaml.Kind
|
CreateKind yaml.Kind
|
||||||
|
|
||||||
|
// CreateTag is used to set the tag if encountering a null field
|
||||||
|
CreateTag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||||
@@ -48,10 +33,11 @@ func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
// apply this FieldSpec
|
// apply this FieldSpec
|
||||||
// create a new filter for each iteration because they
|
// create a new filter for each iteration because they
|
||||||
// store internal state about the field paths
|
// store internal state about the field paths
|
||||||
_, err := (&fieldSpecFilter{
|
_, err := (&fieldspec.Filter{
|
||||||
FieldSpec: fltr.FsSlice[i],
|
FieldSpec: fltr.FsSlice[i],
|
||||||
SetValue: fltr.SetValue,
|
SetValue: fltr.SetValue,
|
||||||
CreateKind: fltr.CreateKind,
|
CreateKind: fltr.CreateKind,
|
||||||
|
CreateTag: fltr.CreateTag,
|
||||||
}).Filter(obj)
|
}).Filter(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -59,20 +45,3 @@ func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGVK parses the metadata into a GVK
|
|
||||||
func GetGVK(meta yaml.ResourceMeta) resid.Gvk {
|
|
||||||
// parse the group and version from the apiVersion field
|
|
||||||
var group, version string
|
|
||||||
parts := strings.SplitN(meta.APIVersion, "/", 2)
|
|
||||||
group = parts[0]
|
|
||||||
if len(parts) > 1 {
|
|
||||||
version = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return resid.Gvk{
|
|
||||||
Group: group,
|
|
||||||
Version: version,
|
|
||||||
Kind: meta.Kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,290 +9,77 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
. "sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
name string
|
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter fsslice.Filter
|
filter Filter
|
||||||
fsSlice string
|
fsSlice string
|
||||||
error string
|
error string
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = []TestCase{
|
var tests = map[string]TestCase{
|
||||||
{
|
"empty": {
|
||||||
name: "update",
|
fsSlice: `
|
||||||
|
`,
|
||||||
|
input: `
|
||||||
|
apiVersion: foo/v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: foo/v1
|
||||||
|
kind: Bar
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
|
CreateKind: yaml.ScalarNode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"two": {
|
||||||
fsSlice: `
|
fsSlice: `
|
||||||
- path: a/b
|
- path: a/b
|
||||||
group: foo
|
group: foo
|
||||||
|
version: v1
|
||||||
|
create: true
|
||||||
|
kind: Bar
|
||||||
|
- path: q/r[]/s/t
|
||||||
|
group: foo
|
||||||
|
version: v1
|
||||||
|
create: true
|
||||||
kind: Bar
|
kind: Bar
|
||||||
`,
|
`,
|
||||||
input: `
|
input: `
|
||||||
apiVersion: foo/v1beta1
|
apiVersion: foo/v1
|
||||||
kind: Bar
|
kind: Bar
|
||||||
a:
|
q:
|
||||||
b: c
|
r:
|
||||||
|
- s: {}
|
||||||
`,
|
`,
|
||||||
expected: `
|
expected: `
|
||||||
apiVersion: foo/v1beta1
|
apiVersion: foo/v1
|
||||||
kind: Bar
|
kind: Bar
|
||||||
|
q:
|
||||||
|
r:
|
||||||
|
- s: {t: e}
|
||||||
a:
|
a:
|
||||||
b: e
|
b: e
|
||||||
`,
|
`,
|
||||||
filter: fsslice.Filter{
|
filter: Filter{
|
||||||
SetValue: fsslice.SetScalar("e"),
|
SetValue: filtersutil.SetScalar("e"),
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "update-kind-not-match",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b
|
|
||||||
group: foo
|
|
||||||
kind: Bar1
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar2
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar2
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "update-group-not-match",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b
|
|
||||||
group: foo1
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo2/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo2/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "update-version-not-match",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b
|
|
||||||
group: foo
|
|
||||||
version: v1beta1
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta2
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta2
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "bad-version",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b
|
|
||||||
group: foo
|
|
||||||
version: v1beta1
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta2/something
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta2/something
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "bad-meta",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b
|
|
||||||
group: foo
|
|
||||||
version: v1beta1
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
a:
|
|
||||||
b: c
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
error: "missing Resource metadata",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "miss-match-type",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b/c
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b: a
|
|
||||||
`,
|
|
||||||
error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node",
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "add",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b/c/d
|
|
||||||
group: foo
|
|
||||||
create: true
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a: {}
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a: {b: {c: {d: e}}}
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
CreateKind: yaml.ScalarNode,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "update-in-sequence",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b[]/c/d
|
|
||||||
group: foo
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
- c:
|
|
||||||
d: a
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
- c:
|
|
||||||
d: e
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Don't create a sequence
|
|
||||||
{
|
|
||||||
name: "empty-sequence-no-create",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b[]/c/d
|
|
||||||
group: foo
|
|
||||||
create: true
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a: {}
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a: {}
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
CreateKind: yaml.ScalarNode,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Create a new field for an element in a sequence
|
|
||||||
{
|
|
||||||
name: "empty-sequence-create",
|
|
||||||
fsSlice: `
|
|
||||||
- path: a/b[]/c/d
|
|
||||||
group: foo
|
|
||||||
create: true
|
|
||||||
kind: Bar
|
|
||||||
`,
|
|
||||||
input: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
- c: {}
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: foo/v1beta1
|
|
||||||
kind: Bar
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
- c: {d: e}
|
|
||||||
`,
|
|
||||||
filter: fsslice.Filter{
|
|
||||||
SetValue: fsslice.SetScalar("e"),
|
|
||||||
CreateKind: yaml.ScalarNode,
|
CreateKind: yaml.ScalarNode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilter_Filter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
for i := range tests {
|
for name := range tests {
|
||||||
test := tests[i]
|
test := tests[name]
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice)
|
err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
@@ -332,23 +119,3 @@ func TestFilter_Filter(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetGVK(t *testing.T) {
|
|
||||||
obj, err := yaml.Parse(`
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
`)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
meta, err := obj.GetMeta()
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
gvk := fsslice.GetGVK(meta)
|
|
||||||
expected := resid.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
|
||||||
if !assert.Equal(t, expected, gvk) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
3
api/filters/iampolicygenerator/doc.go
Normal file
3
api/filters/iampolicygenerator/doc.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Package gkesagenerator contains a kio.Filter that that generates a
|
||||||
|
// iampolicy-related resources for a given cloud provider
|
||||||
|
package iampolicygenerator
|
||||||
46
api/filters/iampolicygenerator/example_test.go
Normal file
46
api/filters/iampolicygenerator/example_test.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package iampolicygenerator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
f := Filter{}
|
||||||
|
var err = yaml.Unmarshal([]byte(`
|
||||||
|
cloud: gke
|
||||||
|
kubernetesService:
|
||||||
|
namespace: k8s-namespace
|
||||||
|
name: k8s-sa-name
|
||||||
|
serviceAccount:
|
||||||
|
name: gsa-name
|
||||||
|
projectId: project-id
|
||||||
|
`), &f)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{},
|
||||||
|
Filters: []kio.Filter{f},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: v1
|
||||||
|
// kind: ServiceAccount
|
||||||
|
// metadata:
|
||||||
|
// annotations:
|
||||||
|
// iam.gke.io/gcp-service-account: gsa-name@project-id.iam.gserviceaccount.com
|
||||||
|
// name: k8s-sa-name
|
||||||
|
// namespace: k8s-namespace
|
||||||
|
}
|
||||||
55
api/filters/iampolicygenerator/iampolicygenerator.go
Normal file
55
api/filters/iampolicygenerator/iampolicygenerator.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package iampolicygenerator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
IAMPolicyGenerator types.IAMPolicyGeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter adds a GKE service account object to nodes
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
switch f.IAMPolicyGenerator.Cloud {
|
||||||
|
case types.GKE:
|
||||||
|
IAMPolicyResources, err := f.generateGkeIAMPolicyResources()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nodes = append(nodes, IAMPolicyResources...)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("cloud provider %s not supported yet", f.IAMPolicyGenerator.Cloud)
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) generateGkeIAMPolicyResources() ([]*yaml.RNode, error) {
|
||||||
|
var result []*yaml.RNode
|
||||||
|
input := fmt.Sprintf(`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
iam.gke.io/gcp-service-account: %s@%s.iam.gserviceaccount.com
|
||||||
|
name: %s
|
||||||
|
`, f.IAMPolicyGenerator.ServiceAccount.Name,
|
||||||
|
f.IAMPolicyGenerator.ProjectId,
|
||||||
|
f.IAMPolicyGenerator.KubernetesService.Name)
|
||||||
|
|
||||||
|
if f.IAMPolicyGenerator.Namespace != "" {
|
||||||
|
input = input + fmt.Sprintf("\n namespace: %s", f.IAMPolicyGenerator.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
sa, err := yaml.Parse(input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(result, sa), nil
|
||||||
|
}
|
||||||
75
api/filters/iampolicygenerator/iampolicygenerator_test.go
Normal file
75
api/filters/iampolicygenerator/iampolicygenerator_test.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package iampolicygenerator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
args types.IAMPolicyGeneratorArgs
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
"with namespace": {
|
||||||
|
args: types.IAMPolicyGeneratorArgs{
|
||||||
|
Cloud: types.GKE,
|
||||||
|
KubernetesService: types.KubernetesService{
|
||||||
|
Namespace: "k8s-namespace",
|
||||||
|
Name: "k8s-sa-name",
|
||||||
|
},
|
||||||
|
ServiceAccount: types.ServiceAccount{
|
||||||
|
Name: "gsa-name",
|
||||||
|
ProjectId: "project-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
iam.gke.io/gcp-service-account: gsa-name@project-id.iam.gserviceaccount.com
|
||||||
|
name: k8s-sa-name
|
||||||
|
namespace: k8s-namespace
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"without namespace": {
|
||||||
|
args: types.IAMPolicyGeneratorArgs{
|
||||||
|
Cloud: types.GKE,
|
||||||
|
KubernetesService: types.KubernetesService{
|
||||||
|
Name: "k8s-sa-name",
|
||||||
|
},
|
||||||
|
ServiceAccount: types.ServiceAccount{
|
||||||
|
Name: "gsa-name",
|
||||||
|
ProjectId: "project-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
iam.gke.io/gcp-service-account: gsa-name@project-id.iam.gserviceaccount.com
|
||||||
|
name: k8s-sa-name
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
f := Filter{
|
||||||
|
IAMPolicyGenerator: tc.args,
|
||||||
|
}
|
||||||
|
actual := filtertest.RunFilter(t, "", f)
|
||||||
|
if !assert.Equal(t, strings.TrimSpace(tc.expected), strings.TrimSpace(actual)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
12
api/filters/imagetag/doc.go
Normal file
12
api/filters/imagetag/doc.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package imagetag contains two kio.Filter implementations to cover the
|
||||||
|
// functionality of the kustomize imagetag transformer.
|
||||||
|
//
|
||||||
|
// Filter updates fields based on a FieldSpec and an ImageTag.
|
||||||
|
//
|
||||||
|
// LegacyFilter doesn't use a FieldSpec, and instead only updates image
|
||||||
|
// references if the field is name image and it is underneath a field called
|
||||||
|
// either containers or initContainers.
|
||||||
|
package imagetag
|
||||||
126
api/filters/imagetag/example_test.go
Normal file
126
api/filters/imagetag/example_test.go
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: FooBar
|
||||||
|
image: nginx
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: BarFoo
|
||||||
|
image: nginx:1.2.1
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
Digest: "12345",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// containers:
|
||||||
|
// - name: FooBar
|
||||||
|
// image: apache@12345
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Bar
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// containers:
|
||||||
|
// - name: BarFoo
|
||||||
|
// image: apache@12345
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleLegacyFilter() {
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: FooBar
|
||||||
|
image: nginx
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: BarFoo
|
||||||
|
image: nginx:1.2.1
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{LegacyFilter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
Digest: "12345",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// containers:
|
||||||
|
// - name: FooBar
|
||||||
|
// image: apache@12345
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Bar
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// containers:
|
||||||
|
// - name: BarFoo
|
||||||
|
// image: apache@12345
|
||||||
|
}
|
||||||
69
api/filters/imagetag/imagetag.go
Normal file
69
api/filters/imagetag/imagetag.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter modifies an "image tag", the value used to specify the
|
||||||
|
// name, tag, version digest etc. of (docker) container images
|
||||||
|
// used by a pod template.
|
||||||
|
type Filter struct {
|
||||||
|
// imageTag is the tag we want to apply to the inputs
|
||||||
|
// The name of the image is used as a key, and other fields
|
||||||
|
// can specify a new name, tag, etc.
|
||||||
|
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||||
|
|
||||||
|
// FsSlice contains the FieldSpecs to locate an image field,
|
||||||
|
// e.g. Path: "spec/myContainers[]/image"
|
||||||
|
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
_, err := kio.FilterAll(yaml.FilterFunc(f.filter)).Filter(nodes)
|
||||||
|
return nodes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
// FsSlice is an allowlist, not a denyList, so to deny
|
||||||
|
// something via configuration a new config mechanism is
|
||||||
|
// needed. Until then, hardcode it.
|
||||||
|
if f.isOnDenyList(node) {
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
if err := node.PipeE(fsslice.Filter{
|
||||||
|
FsSlice: f.FsSlice,
|
||||||
|
SetValue: updateImageTagFn(f.ImageTag),
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) isOnDenyList(node *yaml.RNode) bool {
|
||||||
|
meta, err := node.GetMeta()
|
||||||
|
if err != nil {
|
||||||
|
// A missing 'meta' field will cause problems elsewhere;
|
||||||
|
// ignore it here to keep the signature simple.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Ignore CRDs
|
||||||
|
// https://github.com/kubernetes-sigs/kustomize/issues/890
|
||||||
|
return meta.Kind == `CustomResourceDefinition`
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateImageTagFn(imageTag types.Image) filtersutil.SetFn {
|
||||||
|
return func(node *yaml.RNode) error {
|
||||||
|
return node.PipeE(imageTagUpdater{
|
||||||
|
ImageTag: imageTag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
674
api/filters/imagetag/imagetag_test.go
Normal file
674
api/filters/imagetag/imagetag_test.go
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImageTagUpdater_Filter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expectedOutput string
|
||||||
|
filter Filter
|
||||||
|
fsSlice types.FsSlice
|
||||||
|
}{
|
||||||
|
"ignore CustomResourceDefinition": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: whatever
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: whatever
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: whatever
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: whatever
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "whatever",
|
||||||
|
NewName: "theImageShouldNotChangeInACrd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"legacy multiple images in containers": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: nginx:2.1.2
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache@12345
|
||||||
|
- image: apache@12345
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
Digest: "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"legacy both containers and initContainers": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
initContainers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
initContainers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
NewTag: "3.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/initContainers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"legacy updates at multiple depths": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
NewTag: "3.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"update with digest": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
image: nginx:1.2.1
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
image: apache@12345
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
Digest: "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"multiple matches in sequence": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: not_nginx@54321
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: not_nginx@54321
|
||||||
|
- image: apache:3.2.1
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
NewTag: "3.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"new Tag": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx:v2
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewTag: "v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers[]/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"newImage": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "busybox",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers[]/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"newImageAndTag": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox:v3
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox:v3
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox:v3
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox:v3
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "busybox",
|
||||||
|
NewTag: "v3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers[]/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"newDigest": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:222222222222222222
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
Digest: "sha256:222222222222222222",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"newImageAndDigest": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-notag
|
||||||
|
- image: busybox@sha256:222222222222222222
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "busybox",
|
||||||
|
Digest: "sha256:222222222222222222",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers[]/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"emptyContainers": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
containers: []
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewTag: "v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/containers[]/image",
|
||||||
|
// CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tagWithBraces": {
|
||||||
|
input: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: some.registry.io/my-image:{GENERATED_TAG}
|
||||||
|
name: my-image
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
group: apps
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: some.registry.io/my-image:my-fixed-tag
|
||||||
|
name: my-image
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "some.registry.io/my-image",
|
||||||
|
NewTag: "my-fixed-tag",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/containers[]/image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "spec/template/spec/initContainers[]/image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
filter := tc.filter
|
||||||
|
filter.FsSlice = tc.fsSlice
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expectedOutput),
|
||||||
|
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
105
api/filters/imagetag/legacy.go
Normal file
105
api/filters/imagetag/legacy.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LegacyFilter is an implementation of the kio.Filter interface
|
||||||
|
// that scans through the provided kyaml data structure and updates
|
||||||
|
// any values of any image fields that is inside a sequence under
|
||||||
|
// a field called either containers or initContainers. The field is only
|
||||||
|
// update if it has a value that matches and image reference and the name
|
||||||
|
// of the image is a match with the provided ImageTag.
|
||||||
|
type LegacyFilter struct {
|
||||||
|
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ kio.Filter = LegacyFilter{}
|
||||||
|
|
||||||
|
func (lf LegacyFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
return kio.FilterAll(yaml.FilterFunc(lf.filter)).Filter(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf LegacyFilter) filter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
meta, err := node.GetMeta()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not make any changes if the type of the resource
|
||||||
|
// is CustomResourceDefinition.
|
||||||
|
if meta.Kind == `CustomResourceDefinition` {
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fff := findFieldsFilter{
|
||||||
|
fields: []string{"containers", "initContainers"},
|
||||||
|
fieldCallback: checkImageTagsFn(lf.ImageTag),
|
||||||
|
}
|
||||||
|
if err := node.PipeE(fff); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fieldCallback func(node *yaml.RNode) error
|
||||||
|
|
||||||
|
// findFieldsFilter is an implementation of the kio.Filter
|
||||||
|
// interface. It will walk the data structure and look for fields
|
||||||
|
// that matches the provided list of field names. For each match,
|
||||||
|
// the value of the field will be passed in as a parameter to the
|
||||||
|
// provided fieldCallback.
|
||||||
|
// TODO: move this to kyaml/filterutils
|
||||||
|
type findFieldsFilter struct {
|
||||||
|
fields []string
|
||||||
|
|
||||||
|
fieldCallback fieldCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f findFieldsFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
return obj, f.walk(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f findFieldsFilter) walk(node *yaml.RNode) error {
|
||||||
|
switch node.YNode().Kind {
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return node.VisitFields(func(n *yaml.MapNode) error {
|
||||||
|
err := f.walk(n.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key := n.Key.YNode().Value
|
||||||
|
if utils.StringSliceContains(f.fields, key) {
|
||||||
|
return f.fieldCallback(n.Value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return node.VisitElements(func(n *yaml.RNode) error {
|
||||||
|
return f.walk(n)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkImageTagsFn(imageTag types.Image) fieldCallback {
|
||||||
|
return func(node *yaml.RNode) error {
|
||||||
|
if node.YNode().Kind != yaml.SequenceNode {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.VisitElements(func(n *yaml.RNode) error {
|
||||||
|
// Look up any fields on the provided node that is named
|
||||||
|
// image.
|
||||||
|
return n.PipeE(yaml.Get("image"), imageTagUpdater{
|
||||||
|
ImageTag: imageTag,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
136
api/filters/imagetag/legacy_test.go
Normal file
136
api/filters/imagetag/legacy_test.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLegacyImageTag_Filter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expectedOutput string
|
||||||
|
filter LegacyFilter
|
||||||
|
}{
|
||||||
|
"updates multiple images inside containers": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: nginx:2.1.2
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache@12345
|
||||||
|
- image: apache@12345
|
||||||
|
`,
|
||||||
|
filter: LegacyFilter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
Digest: "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"updates inside both containers and initContainers": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
initContainers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
initContainers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
filter: LegacyFilter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
NewTag: "3.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"updates on multiple depths": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- image: nginx:1.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: tomcat:1.2.3
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- image: apache:3.2.1
|
||||||
|
- image: apache:1.2.3
|
||||||
|
`,
|
||||||
|
filter: LegacyFilter{
|
||||||
|
ImageTag: types.Image{
|
||||||
|
Name: "nginx",
|
||||||
|
NewName: "apache",
|
||||||
|
NewTag: "3.2.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
filter := tc.filter
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expectedOutput),
|
||||||
|
strings.TrimSpace(filtertest.RunFilter(t, tc.input, filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
43
api/filters/imagetag/updater.go
Normal file
43
api/filters/imagetag/updater.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package imagetag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/image"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// imageTagUpdater is an implementation of the kio.Filter interface
|
||||||
|
// that will update the value of the yaml node based on the provided
|
||||||
|
// ImageTag if the current value matches the format of an image reference.
|
||||||
|
type imageTagUpdater struct {
|
||||||
|
Kind string `yaml:"kind,omitempty"`
|
||||||
|
ImageTag types.Image `yaml:"imageTag,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u imageTagUpdater) Filter(rn *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
if err := yaml.ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := rn.YNode().Value
|
||||||
|
|
||||||
|
if !image.IsImageMatched(value, u.ImageTag.Name) {
|
||||||
|
return rn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name, tag := image.Split(value)
|
||||||
|
if u.ImageTag.NewName != "" {
|
||||||
|
name = u.ImageTag.NewName
|
||||||
|
}
|
||||||
|
if u.ImageTag.NewTag != "" {
|
||||||
|
tag = ":" + u.ImageTag.NewTag
|
||||||
|
}
|
||||||
|
if u.ImageTag.Digest != "" {
|
||||||
|
tag = "@" + u.ImageTag.Digest
|
||||||
|
}
|
||||||
|
|
||||||
|
return rn.Pipe(yaml.FieldSetter{StringValue: name + tag})
|
||||||
|
}
|
||||||
@@ -25,14 +25,16 @@ type Filter struct {
|
|||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
keys := filtersutil.SortedMapKeys(f.Labels)
|
keys := yaml.SortedMapKeys(f.Labels)
|
||||||
_, err := kio.FilterAll(yaml.FilterFunc(
|
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||||
func(node *yaml.RNode) (*yaml.RNode, error) {
|
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if err := node.PipeE(fsslice.Filter{
|
if err := node.PipeE(fsslice.Filter{
|
||||||
FsSlice: f.FsSlice,
|
FsSlice: f.FsSlice,
|
||||||
SetValue: fsslice.SetEntry(k, f.Labels[k]),
|
SetValue: filtersutil.SetEntry(
|
||||||
|
k, f.Labels[k], yaml.NodeTagString),
|
||||||
CreateKind: yaml.MappingNode, // Labels are MappingNodes.
|
CreateKind: yaml.MappingNode, // Labels are MappingNodes.
|
||||||
|
CreateTag: yaml.NodeTagMap,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,16 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
|
||||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var labelsFs = builtinconfig.MakeDefaultConfig().CommonLabels
|
|
||||||
|
|
||||||
func TestLabels_Filter(t *testing.T) {
|
func TestLabels_Filter(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expectedOutput string
|
expectedOutput string
|
||||||
filter Filter
|
filter Filter
|
||||||
fsSlice types.FsSlice
|
|
||||||
}{
|
}{
|
||||||
"add": {
|
"add": {
|
||||||
input: `
|
input: `
|
||||||
@@ -45,12 +42,20 @@ metadata:
|
|||||||
clown: emmett kelley
|
clown: emmett kelley
|
||||||
dragon: smaug
|
dragon: smaug
|
||||||
`,
|
`,
|
||||||
filter: Filter{Labels: labelMap{
|
filter: Filter{
|
||||||
"clown": "emmett kelley",
|
Labels: labelMap{
|
||||||
"auto": "ford",
|
"clown": "emmett kelley",
|
||||||
"dragon": "smaug",
|
"auto": "ford",
|
||||||
"bean": "cannellini",
|
"dragon": "smaug",
|
||||||
}},
|
"bean": "cannellini",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
input: `
|
input: `
|
||||||
@@ -73,13 +78,21 @@ metadata:
|
|||||||
bean: cannellini
|
bean: cannellini
|
||||||
clown: emmett kelley
|
clown: emmett kelley
|
||||||
`,
|
`,
|
||||||
filter: Filter{Labels: labelMap{
|
filter: Filter{
|
||||||
"clown": "emmett kelley",
|
Labels: labelMap{
|
||||||
"hero": "superman",
|
"clown": "emmett kelley",
|
||||||
"fiend": "luthor",
|
"hero": "superman",
|
||||||
"bean": "cannellini",
|
"fiend": "luthor",
|
||||||
}},
|
"bean": "cannellini",
|
||||||
|
}, FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"data-fieldspecs": {
|
"data-fieldspecs": {
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
@@ -113,13 +126,276 @@ a:
|
|||||||
b:
|
b:
|
||||||
sleater: kinney
|
sleater: kinney
|
||||||
`,
|
`,
|
||||||
filter: Filter{Labels: labelMap{
|
filter: Filter{
|
||||||
"sleater": "kinney",
|
Labels: labelMap{
|
||||||
}},
|
"sleater": "kinney",
|
||||||
fsSlice: []types.FieldSpec{
|
},
|
||||||
{
|
FsSlice: []types.FieldSpec{
|
||||||
Path: "a/b",
|
{
|
||||||
CreateIfNotPresent: true,
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "a/b",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"fieldSpecWithKind": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
cheese: cheddar
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"cheese": "cheddar",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Gvk: resid.Gvk{
|
||||||
|
Kind: "Bar",
|
||||||
|
},
|
||||||
|
Path: "a/b",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"fieldSpecWithVersion": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
cheese: cheddar
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"cheese": "cheddar",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Gvk: resid.Gvk{
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
Path: "a/b",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"fieldSpecWithVersionInConfigButNoGroupInData": {
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
cheese: cheddar
|
||||||
|
---
|
||||||
|
apiVersion: v2
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
cheese: cheddar
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"cheese": "cheddar",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Gvk: resid.Gvk{
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
Path: "a/b",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"number": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
1: emmett kelley
|
||||||
|
auto: "2"
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"1": "emmett kelley",
|
||||||
|
"auto": "2",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// test quoting of values which are not considered strings in yaml 1.1
|
||||||
|
"yaml_1_1_compatibility": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
hero: batman
|
||||||
|
fiend: riddler
|
||||||
|
a: "y"
|
||||||
|
b: y1
|
||||||
|
c: "yes"
|
||||||
|
d: yes1
|
||||||
|
e: "true"
|
||||||
|
f: true1
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"a": "y",
|
||||||
|
"b": "y1",
|
||||||
|
"c": "yes",
|
||||||
|
"d": "yes1",
|
||||||
|
"e": "true",
|
||||||
|
"f": "true1",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"null_labels": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels: null
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
labels:
|
||||||
|
a: a1
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Labels: labelMap{
|
||||||
|
"a": "a1",
|
||||||
|
},
|
||||||
|
FsSlice: []types.FieldSpec{
|
||||||
|
{
|
||||||
|
Path: "metadata/labels",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -127,11 +403,9 @@ a:
|
|||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
filter := tc.filter
|
|
||||||
filter.FsSlice = append(labelsFs, tc.fsSlice...)
|
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(tc.expectedOutput),
|
strings.TrimSpace(tc.expectedOutput),
|
||||||
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
3
api/filters/nameref/doc.go
Normal file
3
api/filters/nameref/doc.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Package nameref contains a kio.Filter implementation of the kustomize
|
||||||
|
// name reference transformer.
|
||||||
|
package nameref
|
||||||
396
api/filters/nameref/nameref.go
Normal file
396
api/filters/nameref/nameref.go
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
package nameref
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter updates a name references.
|
||||||
|
type Filter struct {
|
||||||
|
// Referrer refers to another resource X by X's name.
|
||||||
|
// E.g. A Deployment can refer to a ConfigMap.
|
||||||
|
// The Deployment is the Referrer,
|
||||||
|
// the ConfigMap is the ReferralTarget.
|
||||||
|
// This filter seeks to repair the reference in Deployment, given
|
||||||
|
// that the ConfigMap's name may have changed.
|
||||||
|
Referrer *resource.Resource
|
||||||
|
|
||||||
|
// NameFieldToUpdate is the field in the Referrer
|
||||||
|
// that holds the name requiring an update.
|
||||||
|
// This is the field to write.
|
||||||
|
NameFieldToUpdate types.FieldSpec
|
||||||
|
|
||||||
|
// ReferralTarget is the source of the new value for
|
||||||
|
// the name, always in the 'metadata/name' field.
|
||||||
|
// This is the field to read.
|
||||||
|
ReferralTarget resid.Gvk
|
||||||
|
|
||||||
|
// Set of resources to scan to find the ReferralTarget.
|
||||||
|
ReferralCandidates resmap.ResMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// At time of writing, in practice this is called with a slice with only
|
||||||
|
// one entry, the node also referred to be the resource in the Referrer field.
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The node passed in here is the same node as held in Referrer;
|
||||||
|
// that's how the referrer's name field is updated.
|
||||||
|
// Currently, however, this filter still needs the extra methods on Referrer
|
||||||
|
// to consult things like the resource Id, its namespace, etc.
|
||||||
|
// TODO(3455): No filter should use the Resource api; all information
|
||||||
|
// about names should come from annotations, with helper methods
|
||||||
|
// on the RNode object. Resource should get stupider, RNode smarter.
|
||||||
|
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
if err := f.confirmNodeMatchesReferrer(node); err != nil {
|
||||||
|
// sanity check.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f.NameFieldToUpdate.Gvk = f.Referrer.GetGvk()
|
||||||
|
if err := node.PipeE(fieldspec.Filter{
|
||||||
|
FieldSpec: f.NameFieldToUpdate,
|
||||||
|
SetValue: f.set,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, errors.Wrapf(
|
||||||
|
err, "updating name reference in '%s' field of '%s'",
|
||||||
|
f.NameFieldToUpdate.Path, f.Referrer.CurId().String())
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called on the node found at FieldSpec.Path.
|
||||||
|
// It's some node in the Referrer.
|
||||||
|
func (f Filter) set(node *yaml.RNode) error {
|
||||||
|
if yaml.IsMissingOrNull(node) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch node.YNode().Kind {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
return f.setScalar(node)
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return f.setMapping(node)
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return applyFilterToSeq(seqFilter{
|
||||||
|
setScalarFn: f.setScalar,
|
||||||
|
setMappingFn: f.setMapping,
|
||||||
|
}, node)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("node must be a scalar, sequence or map")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method used when NameFieldToUpdate doesn't lead to
|
||||||
|
// one scalar field (typically called 'name'), but rather
|
||||||
|
// leads to a map field (called anything). In this case we
|
||||||
|
// must complete the field path, looking for both a 'name'
|
||||||
|
// and a 'namespace' field to help select the proper
|
||||||
|
// ReferralTarget to read the name and namespace from.
|
||||||
|
func (f Filter) setMapping(node *yaml.RNode) error {
|
||||||
|
if node.YNode().Kind != yaml.MappingNode {
|
||||||
|
return fmt.Errorf("expect a mapping node")
|
||||||
|
}
|
||||||
|
nameNode, err := node.Pipe(yaml.FieldMatcher{Name: "name"})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "trying to match 'name' field")
|
||||||
|
}
|
||||||
|
if nameNode == nil {
|
||||||
|
// This is a _configuration_ error; the field path
|
||||||
|
// specified in NameFieldToUpdate.Path doesn't resolve
|
||||||
|
// to a map with a 'name' field, so we have no idea what
|
||||||
|
// field to update with a new name.
|
||||||
|
return fmt.Errorf("path config error; no 'name' field in node")
|
||||||
|
}
|
||||||
|
candidates, err := f.filterMapCandidatesByNamespace(node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oldName := nameNode.YNode().Value
|
||||||
|
referral, err := f.selectReferral(oldName, candidates)
|
||||||
|
if err != nil || referral == nil {
|
||||||
|
// Nil referral means nothing to do.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.recordTheReferral(referral)
|
||||||
|
if referral.GetName() == oldName && referral.GetNamespace() == "" {
|
||||||
|
// The name has not changed, nothing to do.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err = node.PipeE(yaml.FieldSetter{
|
||||||
|
Name: "name",
|
||||||
|
StringValue: referral.GetName(),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if referral.GetNamespace() == "" {
|
||||||
|
// Don't write an empty string into the namespace field, as
|
||||||
|
// it should not replace the value "default". The empty
|
||||||
|
// string is handled as a wild card here, not as an implicit
|
||||||
|
// specification of the "default" k8s namespace.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return node.PipeE(yaml.FieldSetter{
|
||||||
|
Name: "namespace",
|
||||||
|
StringValue: referral.GetNamespace(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) filterMapCandidatesByNamespace(
|
||||||
|
node *yaml.RNode) ([]*resource.Resource, error) {
|
||||||
|
namespaceNode, err := node.Pipe(yaml.FieldMatcher{Name: "namespace"})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "trying to match 'namespace' field")
|
||||||
|
}
|
||||||
|
if namespaceNode == nil {
|
||||||
|
return f.ReferralCandidates.Resources(), nil
|
||||||
|
}
|
||||||
|
namespace := namespaceNode.YNode().Value
|
||||||
|
nsMap := f.ReferralCandidates.GroupedByOriginalNamespace()
|
||||||
|
if candidates, ok := nsMap[namespace]; ok {
|
||||||
|
return candidates, nil
|
||||||
|
}
|
||||||
|
nsMap = f.ReferralCandidates.GroupedByCurrentNamespace()
|
||||||
|
// This could be nil, or an empty list.
|
||||||
|
return nsMap[namespace], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) setScalar(node *yaml.RNode) error {
|
||||||
|
referral, err := f.selectReferral(
|
||||||
|
node.YNode().Value, f.ReferralCandidates.Resources())
|
||||||
|
if err != nil || referral == nil {
|
||||||
|
// Nil referral means nothing to do.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.recordTheReferral(referral)
|
||||||
|
if referral.GetName() == node.YNode().Value {
|
||||||
|
// The name has not changed, nothing to do.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return node.PipeE(yaml.FieldSetter{StringValue: referral.GetName()})
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the resource, make a note that it is referred to by the Referrer.
|
||||||
|
func (f Filter) recordTheReferral(referral *resource.Resource) {
|
||||||
|
referral.AppendRefBy(f.Referrer.CurId())
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRoleRefGvk returns a Gvk in the roleRef field. Return error
|
||||||
|
// if the roleRef, roleRef/apiGroup or roleRef/kind is missing.
|
||||||
|
func getRoleRefGvk(n *resource.Resource) (*resid.Gvk, error) {
|
||||||
|
roleRef, err := n.Pipe(yaml.Lookup("roleRef"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if roleRef.IsNil() {
|
||||||
|
return nil, fmt.Errorf("roleRef cannot be found in %s", n.MustString())
|
||||||
|
}
|
||||||
|
apiGroup, err := roleRef.Pipe(yaml.Lookup("apiGroup"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if apiGroup.IsNil() {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"apiGroup cannot be found in roleRef %s", roleRef.MustString())
|
||||||
|
}
|
||||||
|
kind, err := roleRef.Pipe(yaml.Lookup("kind"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if kind.IsNil() {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"kind cannot be found in roleRef %s", roleRef.MustString())
|
||||||
|
}
|
||||||
|
return &resid.Gvk{
|
||||||
|
Group: apiGroup.YNode().Value,
|
||||||
|
Kind: kind.YNode().Value,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sieveFunc returns true if the resource argument satisfies some criteria.
|
||||||
|
type sieveFunc func(*resource.Resource) bool
|
||||||
|
|
||||||
|
// doSieve uses a function to accept or ignore resources from a list.
|
||||||
|
// If list is nil, returns immediately.
|
||||||
|
// It's a filter obviously, but that term is overloaded here.
|
||||||
|
func doSieve(list []*resource.Resource, fn sieveFunc) (s []*resource.Resource) {
|
||||||
|
for _, r := range list {
|
||||||
|
if fn(r) {
|
||||||
|
s = append(s, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func acceptAll(r *resource.Resource) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func previousNameMatches(name string) sieveFunc {
|
||||||
|
return func(r *resource.Resource) bool {
|
||||||
|
for _, id := range r.PrevIds() {
|
||||||
|
if id.Name == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func previousIdSelectedByGvk(gvk *resid.Gvk) sieveFunc {
|
||||||
|
return func(r *resource.Resource) bool {
|
||||||
|
for _, id := range r.PrevIds() {
|
||||||
|
if id.IsSelected(gvk) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the we are updating a 'roleRef/name' field, the 'apiGroup' and 'kind'
|
||||||
|
// fields in the same 'roleRef' map must be considered.
|
||||||
|
// If either object is cluster-scoped, there can be a referral.
|
||||||
|
// E.g. a RoleBinding (which exists in a namespace) can refer
|
||||||
|
// to a ClusterRole (cluster-scoped) object.
|
||||||
|
// https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole
|
||||||
|
// Likewise, a ClusterRole can refer to a Secret (in a namespace).
|
||||||
|
// Objects in different namespaces generally cannot refer to other
|
||||||
|
// with some exceptions (e.g. RoleBinding and ServiceAccount are both
|
||||||
|
// namespaceable, but the former can refer to accounts in other namespaces).
|
||||||
|
func (f Filter) roleRefFilter() sieveFunc {
|
||||||
|
if !strings.HasSuffix(f.NameFieldToUpdate.Path, "roleRef/name") {
|
||||||
|
return acceptAll
|
||||||
|
}
|
||||||
|
roleRefGvk, err := getRoleRefGvk(f.Referrer)
|
||||||
|
if err != nil {
|
||||||
|
return acceptAll
|
||||||
|
}
|
||||||
|
return previousIdSelectedByGvk(roleRefGvk)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixSuffixEquals(other resource.ResCtx) sieveFunc {
|
||||||
|
return func(r *resource.Resource) bool {
|
||||||
|
return r.PrefixesSuffixesEquals(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) sameCurrentNamespaceAsReferrer() sieveFunc {
|
||||||
|
referrerCurId := f.Referrer.CurId()
|
||||||
|
if referrerCurId.IsClusterScoped() {
|
||||||
|
// If the referrer is cluster-scoped, let anything through.
|
||||||
|
return acceptAll
|
||||||
|
}
|
||||||
|
return func(r *resource.Resource) bool {
|
||||||
|
if r.CurId().IsClusterScoped() {
|
||||||
|
// Allow cluster-scoped through.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if r.GetKind() == "ServiceAccount" {
|
||||||
|
// Allow service accounts through, even though they
|
||||||
|
// are in a namespace. A RoleBinding in another namespace
|
||||||
|
// can reference them.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return referrerCurId.IsNsEquals(r.CurId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectReferral picks the best referral from a list of candidates.
|
||||||
|
func (f Filter) selectReferral(
|
||||||
|
// The name referral that may need to be updated.
|
||||||
|
oldName string,
|
||||||
|
candidates []*resource.Resource) (*resource.Resource, error) {
|
||||||
|
candidates = doSieve(candidates, previousNameMatches(oldName))
|
||||||
|
candidates = doSieve(candidates, previousIdSelectedByGvk(&f.ReferralTarget))
|
||||||
|
candidates = doSieve(candidates, f.roleRefFilter())
|
||||||
|
candidates = doSieve(candidates, f.sameCurrentNamespaceAsReferrer())
|
||||||
|
if len(candidates) == 1 {
|
||||||
|
return candidates[0], nil
|
||||||
|
}
|
||||||
|
candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer))
|
||||||
|
if len(candidates) == 1 {
|
||||||
|
return candidates[0], nil
|
||||||
|
}
|
||||||
|
if len(candidates) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if allNamesAreTheSame(candidates) {
|
||||||
|
// Just take the first one.
|
||||||
|
return candidates[0], nil
|
||||||
|
}
|
||||||
|
ids := getIds(candidates)
|
||||||
|
f.failureDetails(candidates)
|
||||||
|
return nil, fmt.Errorf(" found multiple possible referrals: %s", ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) failureDetails(resources []*resource.Resource) {
|
||||||
|
fmt.Printf(
|
||||||
|
"\n**** Too many possible referral targets to referrer:\n%s\n",
|
||||||
|
f.Referrer.MustYaml())
|
||||||
|
for i, r := range resources {
|
||||||
|
fmt.Printf(
|
||||||
|
"--- possible referral %d:\n%s", i, r.MustYaml())
|
||||||
|
fmt.Println("------")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func allNamesAreTheSame(resources []*resource.Resource) bool {
|
||||||
|
name := resources[0].GetName()
|
||||||
|
for i := 1; i < len(resources); i++ {
|
||||||
|
if name != resources[i].GetName() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIds(rs []*resource.Resource) string {
|
||||||
|
var result []string
|
||||||
|
for _, r := range rs {
|
||||||
|
result = append(result, r.CurId().String())
|
||||||
|
}
|
||||||
|
return strings.Join(result, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkEqual(k, a, b string) error {
|
||||||
|
if a != b {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"node-referrerOriginal '%s' mismatch '%s' != '%s'",
|
||||||
|
k, a, b)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) confirmNodeMatchesReferrer(node *yaml.RNode) error {
|
||||||
|
meta, err := node.GetMeta()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gvk := f.Referrer.GetGvk()
|
||||||
|
if err = checkEqual(
|
||||||
|
"APIVersion", meta.APIVersion, gvk.ApiVersion()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = checkEqual(
|
||||||
|
"Kind", meta.Kind, gvk.Kind); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = checkEqual(
|
||||||
|
"Name", meta.Name, f.Referrer.GetName()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = checkEqual(
|
||||||
|
"Namespace", meta.Namespace, f.Referrer.GetNamespace()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
789
api/filters/nameref/nameref_test.go
Normal file
789
api/filters/nameref/nameref_test.go
Normal file
@@ -0,0 +1,789 @@
|
|||||||
|
package nameref
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNamerefFilter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
referrerOriginal string
|
||||||
|
candidates string
|
||||||
|
referrerFinal string
|
||||||
|
filter Filter
|
||||||
|
originalNames []string
|
||||||
|
}{
|
||||||
|
"simple scalar": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: NotSecret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "newName2"},
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: newName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sequence": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
seq:
|
||||||
|
- oldName1
|
||||||
|
- oldName2
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: NotSecret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName1", "newName2"},
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
seq:
|
||||||
|
- newName
|
||||||
|
- oldName2
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "seq"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"mapping": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
map:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: NotSecret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "newName2"},
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
map:
|
||||||
|
name: newName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "map"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"mapping with namespace": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
namespace: someNs
|
||||||
|
map:
|
||||||
|
name: oldName
|
||||||
|
namespace: someNs
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
namespace: someNs
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: NotSecret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: thirdName
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName", "oldName"},
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
namespace: someNs
|
||||||
|
map:
|
||||||
|
name: newName
|
||||||
|
namespace: someNs
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "map"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"null value": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
map:
|
||||||
|
name: null
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: NotSecret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "newName2"},
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
map:
|
||||||
|
name: null
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "map"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
factory := provider.NewDefaultDepProvider().GetResourceFactory()
|
||||||
|
referrer, err := factory.FromBytes([]byte(tc.referrerOriginal))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tc.filter.Referrer = referrer
|
||||||
|
|
||||||
|
resMapFactory := resmap.NewFactory(factory)
|
||||||
|
candidatesRes, err := factory.SliceFromBytesWithNames(
|
||||||
|
tc.originalNames, []byte(tc.candidates))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates := resMapFactory.FromResourceSlice(candidatesRes)
|
||||||
|
tc.filter.ReferralCandidates = candidates
|
||||||
|
|
||||||
|
result := filtertest_test.RunFilter(t, tc.referrerOriginal, tc.filter)
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.referrerFinal),
|
||||||
|
strings.TrimSpace(result)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamerefFilterUnhappy(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
referrerOriginal string
|
||||||
|
candidates string
|
||||||
|
referrerFinal string
|
||||||
|
filter Filter
|
||||||
|
originalNames []string
|
||||||
|
}{
|
||||||
|
"multiple match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
referrerFinal: "",
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"no name": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
notName: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
referrerFinal: "",
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
factory := provider.NewDefaultDepProvider().GetResourceFactory()
|
||||||
|
referrer, err := factory.FromBytes([]byte(tc.referrerOriginal))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tc.filter.Referrer = referrer
|
||||||
|
|
||||||
|
resMapFactory := resmap.NewFactory(factory)
|
||||||
|
candidatesRes, err := factory.SliceFromBytesWithNames(
|
||||||
|
tc.originalNames, []byte(tc.candidates))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates := resMapFactory.FromResourceSlice(candidatesRes)
|
||||||
|
tc.filter.ReferralCandidates = candidates
|
||||||
|
|
||||||
|
_, err = filtertest_test.RunFilterE(t, tc.referrerOriginal, tc.filter)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expect an error")
|
||||||
|
}
|
||||||
|
if tc.referrerFinal != "" && !assert.EqualError(t, err, tc.referrerFinal) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCandidatesWithDifferentPrefixSuffix(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
referrerOriginal string
|
||||||
|
candidates string
|
||||||
|
referrerFinal string
|
||||||
|
filter Filter
|
||||||
|
originalNames []string
|
||||||
|
prefix []string
|
||||||
|
suffix []string
|
||||||
|
inputPrefix string
|
||||||
|
inputSuffix string
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
"prefix match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix1", "prefix2"},
|
||||||
|
suffix: []string{"", "suffix2"},
|
||||||
|
inputPrefix: "prefix1",
|
||||||
|
inputSuffix: "",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: newName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
"suffix match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"", "prefix2"},
|
||||||
|
suffix: []string{"suffix1", "suffix2"},
|
||||||
|
inputPrefix: "",
|
||||||
|
inputSuffix: "suffix1",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: newName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
"prefix suffix both match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix1", "prefix2"},
|
||||||
|
suffix: []string{"suffix1", "suffix2"},
|
||||||
|
inputPrefix: "prefix1",
|
||||||
|
inputSuffix: "suffix1",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: newName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
"multiple match: both": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix", "prefix"},
|
||||||
|
suffix: []string{"suffix", "suffix"},
|
||||||
|
inputPrefix: "prefix",
|
||||||
|
inputSuffix: "suffix",
|
||||||
|
referrerFinal: "",
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
"multiple match: only prefix": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix", "prefix"},
|
||||||
|
suffix: []string{"", ""},
|
||||||
|
inputPrefix: "prefix",
|
||||||
|
inputSuffix: "",
|
||||||
|
referrerFinal: "",
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
"multiple match: only suffix": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"", ""},
|
||||||
|
suffix: []string{"suffix", "suffix"},
|
||||||
|
inputPrefix: "",
|
||||||
|
inputSuffix: "suffix",
|
||||||
|
referrerFinal: "",
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: true,
|
||||||
|
},
|
||||||
|
"no match: neither match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix1", "prefix2"},
|
||||||
|
suffix: []string{"suffix1", "suffix2"},
|
||||||
|
inputPrefix: "prefix",
|
||||||
|
inputSuffix: "suffix",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
"no match: prefix doesn't match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix1", "prefix2"},
|
||||||
|
suffix: []string{"suffix", "suffix"},
|
||||||
|
inputPrefix: "prefix",
|
||||||
|
inputSuffix: "suffix",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
"no match: suffix doesn't match": {
|
||||||
|
referrerOriginal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
candidates: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: newName2
|
||||||
|
`,
|
||||||
|
originalNames: []string{"oldName", "oldName"},
|
||||||
|
prefix: []string{"prefix", "prefix"},
|
||||||
|
suffix: []string{"suffix1", "suffix2"},
|
||||||
|
inputPrefix: "prefix",
|
||||||
|
inputSuffix: "suffix",
|
||||||
|
referrerFinal: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
ref:
|
||||||
|
name: oldName
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
NameFieldToUpdate: types.FieldSpec{Path: "ref/name"},
|
||||||
|
ReferralTarget: resid.Gvk{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
factory := provider.NewDefaultDepProvider().GetResourceFactory()
|
||||||
|
referrer, err := factory.FromBytes([]byte(tc.referrerOriginal))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if tc.inputPrefix != "" {
|
||||||
|
referrer.AddNamePrefix(tc.inputPrefix)
|
||||||
|
}
|
||||||
|
if tc.inputSuffix != "" {
|
||||||
|
referrer.AddNameSuffix(tc.inputSuffix)
|
||||||
|
}
|
||||||
|
tc.filter.Referrer = referrer
|
||||||
|
|
||||||
|
resMapFactory := resmap.NewFactory(factory)
|
||||||
|
candidatesRes, err := factory.SliceFromBytesWithNames(
|
||||||
|
tc.originalNames, []byte(tc.candidates))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for i := range candidatesRes {
|
||||||
|
if tc.prefix[i] != "" {
|
||||||
|
candidatesRes[i].AddNamePrefix(tc.prefix[i])
|
||||||
|
}
|
||||||
|
if tc.suffix[i] != "" {
|
||||||
|
candidatesRes[i].AddNameSuffix(tc.suffix[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates := resMapFactory.FromResourceSlice(candidatesRes)
|
||||||
|
tc.filter.ReferralCandidates = candidates
|
||||||
|
|
||||||
|
if !tc.err {
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.referrerFinal),
|
||||||
|
strings.TrimSpace(
|
||||||
|
filtertest_test.RunFilter(
|
||||||
|
t, tc.referrerOriginal, tc.filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := filtertest_test.RunFilterE(
|
||||||
|
t, tc.referrerOriginal, tc.filter)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("an error is expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
57
api/filters/nameref/seqfilter.go
Normal file
57
api/filters/nameref/seqfilter.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package nameref
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type setFn func(*yaml.RNode) error
|
||||||
|
|
||||||
|
type seqFilter struct {
|
||||||
|
setScalarFn setFn
|
||||||
|
setMappingFn setFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf seqFilter) Filter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
if yaml.IsMissingOrNull(node) {
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
switch node.YNode().Kind {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
// Kind: Role/ClusterRole
|
||||||
|
// FieldSpec is rules.resourceNames
|
||||||
|
err := sf.setScalarFn(node)
|
||||||
|
return node, err
|
||||||
|
case yaml.MappingNode:
|
||||||
|
// Kind: RoleBinding/ClusterRoleBinding
|
||||||
|
// FieldSpec is subjects
|
||||||
|
// Note: The corresponding fieldSpec had been changed from
|
||||||
|
// from path: subjects/name to just path: subjects. This is
|
||||||
|
// what get mutatefield to request the mapping of the whole
|
||||||
|
// map containing namespace and name instead of just a simple
|
||||||
|
// string field containing the name
|
||||||
|
err := sf.setMappingFn(node)
|
||||||
|
return node, err
|
||||||
|
default:
|
||||||
|
return node, fmt.Errorf(
|
||||||
|
"%#v is expected to be either a string or a map of string", node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyFilterToSeq will apply the filter to each element in the sequence node
|
||||||
|
func applyFilterToSeq(filter yaml.Filter, node *yaml.RNode) error {
|
||||||
|
if node.YNode().Kind != yaml.SequenceNode {
|
||||||
|
return fmt.Errorf("expect a sequence node but got %v", node.YNode().Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, elem := range node.Content() {
|
||||||
|
rnode := yaml.NewRNode(elem)
|
||||||
|
err := rnode.PipeE(filter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
80
api/filters/nameref/seqfilter_test.go
Normal file
80
api/filters/nameref/seqfilter_test.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package nameref
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SeqFilter(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
if node.YNode().Value == "aaa" {
|
||||||
|
node.YNode().SetString("ccc")
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApplyFilterToSeq(t *testing.T) {
|
||||||
|
fltr := yaml.FilterFunc(SeqFilter)
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expect string
|
||||||
|
}{
|
||||||
|
"replace in seq": {
|
||||||
|
input: `
|
||||||
|
- aaa
|
||||||
|
- bbb`,
|
||||||
|
expect: `
|
||||||
|
- ccc
|
||||||
|
- bbb`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
node, err := yaml.Parse(tc.input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = applyFilterToSeq(fltr, node)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expect),
|
||||||
|
strings.TrimSpace(node.MustString())) {
|
||||||
|
t.Fatalf("expect:\n%s\nactual:\n%s",
|
||||||
|
strings.TrimSpace(tc.expect),
|
||||||
|
strings.TrimSpace(node.MustString()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApplyFilterToSeqUnhappy(t *testing.T) {
|
||||||
|
fltr := yaml.FilterFunc(SeqFilter)
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
}{
|
||||||
|
"replace in seq": {
|
||||||
|
input: `
|
||||||
|
aaa`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
node, err := yaml.Parse(tc.input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = applyFilterToSeq(fltr, node)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expect an error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
package namespace
|
package namespace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,8 +44,9 @@ func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
// transformations based on data -- :)
|
// transformations based on data -- :)
|
||||||
err := node.PipeE(fsslice.Filter{
|
err := node.PipeE(fsslice.Filter{
|
||||||
FsSlice: ns.FsSlice,
|
FsSlice: ns.FsSlice,
|
||||||
SetValue: fsslice.SetScalar(ns.Namespace),
|
SetValue: filtersutil.SetScalar(ns.Namespace),
|
||||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||||
|
CreateTag: yaml.NodeTagString,
|
||||||
})
|
})
|
||||||
return node, err
|
return node, err
|
||||||
}
|
}
|
||||||
@@ -51,36 +54,30 @@ func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
|||||||
// hacks applies the namespace transforms that are hardcoded rather
|
// hacks applies the namespace transforms that are hardcoded rather
|
||||||
// than specified through FieldSpecs.
|
// than specified through FieldSpecs.
|
||||||
func (ns Filter) hacks(obj *yaml.RNode) error {
|
func (ns Filter) hacks(obj *yaml.RNode) error {
|
||||||
meta, err := obj.GetMeta()
|
gvk := resid.GvkFromNode(obj)
|
||||||
if err != nil {
|
if err := ns.metaNamespaceHack(obj, gvk); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return ns.roleBindingHack(obj, gvk)
|
||||||
if err := ns.metaNamespaceHack(obj, meta); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ns.roleBindingHack(obj, meta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// metaNamespaceHack is a hack for implementing the namespace transform
|
// metaNamespaceHack is a hack for implementing the namespace transform
|
||||||
// for the metadata.namespace field on namespace scoped resources.
|
// for the metadata.namespace field on namespace scoped resources.
|
||||||
// namespace scoped resources are determined by NOT being present
|
// namespace scoped resources are determined by NOT being present
|
||||||
// in a blacklist of cluster-scoped resource types (by apiVersion and kind).
|
// in a hard-coded list of cluster-scoped resource types (by apiVersion and kind).
|
||||||
//
|
//
|
||||||
// This hack should be updated to allow individual resources to specify
|
// This hack should be updated to allow individual resources to specify
|
||||||
// if they are cluster scoped through either an annotation on the resources,
|
// if they are cluster scoped through either an annotation on the resources,
|
||||||
// or through inlined OpenAPI on the resource as a YAML comment.
|
// or through inlined OpenAPI on the resource as a YAML comment.
|
||||||
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
|
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||||
gvk := fsslice.GetGVK(meta)
|
if gvk.IsClusterScoped() {
|
||||||
if !gvk.IsNamespaceableKind() {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
f := fsslice.Filter{
|
f := fsslice.Filter{
|
||||||
FsSlice: []types.FieldSpec{
|
FsSlice: []types.FieldSpec{
|
||||||
{Path: metaNamespaceField, CreateIfNotPresent: true},
|
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
|
||||||
},
|
},
|
||||||
SetValue: fsslice.SetScalar(ns.Namespace),
|
SetValue: filtersutil.SetScalar(ns.Namespace),
|
||||||
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
|
||||||
}
|
}
|
||||||
_, err := f.Filter(obj)
|
_, err := f.Filter(obj)
|
||||||
@@ -101,28 +98,27 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) erro
|
|||||||
// ...
|
// ...
|
||||||
// - name: "something-else" # this will not have the namespace set
|
// - name: "something-else" # this will not have the namespace set
|
||||||
// ...
|
// ...
|
||||||
func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
|
func (ns Filter) roleBindingHack(obj *yaml.RNode, gvk resid.Gvk) error {
|
||||||
if meta.Kind != roleBindingKind && meta.Kind != clusterRoleBindingKind {
|
if gvk.Kind != roleBindingKind && gvk.Kind != clusterRoleBindingKind {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup the namespace field on all elements.
|
// Lookup the namespace field on all elements.
|
||||||
// We should change the fieldspec so this isn't necessary.
|
// We should change the fieldspec so this isn't necessary.
|
||||||
obj, err := obj.Pipe(yaml.Lookup(subjectsField))
|
obj, err := obj.Pipe(yaml.Lookup(subjectsField))
|
||||||
if err != nil || yaml.IsEmpty(obj) {
|
if err != nil || yaml.IsMissingOrNull(obj) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the namespace to each "subject" with name: default
|
// add the namespace to each "subject" with name: default
|
||||||
err = obj.VisitElements(func(o *yaml.RNode) error {
|
err = obj.VisitElements(func(o *yaml.RNode) error {
|
||||||
// copied from kunstruct based kustomize NamespaceTransformer plugin
|
|
||||||
// The only case we need to force the namespace
|
// The only case we need to force the namespace
|
||||||
// if for the "service account". "default" is
|
// if for the "service account". "default" is
|
||||||
// kind of hardcoded here for right now.
|
// kind of hardcoded here for right now.
|
||||||
name, err := o.Pipe(
|
name, err := o.Pipe(
|
||||||
yaml.Lookup("name"), yaml.Match("default"),
|
yaml.Lookup("name"), yaml.Match("default"),
|
||||||
)
|
)
|
||||||
if err != nil || yaml.IsEmpty(name) {
|
if err != nil || yaml.IsMissingOrNull(name) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +139,7 @@ func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice {
|
|||||||
var val types.FsSlice
|
var val types.FsSlice
|
||||||
for i := range fs {
|
for i := range fs {
|
||||||
// implemented by metaNamespaceHack
|
// implemented by metaNamespaceHack
|
||||||
if fs[i].Path == metaNamespaceField {
|
if fs[i].Path == types.MetadataNamespacePath {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// implemented by roleBindingHack
|
// implemented by roleBindingHack
|
||||||
@@ -160,7 +156,6 @@ func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
metaNamespaceField = "metadata/namespace"
|
|
||||||
subjectsField = "subjects"
|
subjectsField = "subjects"
|
||||||
roleBindingKind = "RoleBinding"
|
roleBindingKind = "RoleBinding"
|
||||||
clusterRoleBindingKind = "ClusterRoleBinding"
|
clusterRoleBindingKind = "ClusterRoleBinding"
|
||||||
|
|||||||
@@ -44,6 +44,37 @@ metadata:
|
|||||||
filter: namespace.Filter{Namespace: "foo"},
|
filter: namespace.Filter{Namespace: "foo"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "null_ns",
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: null
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: null
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: foo
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: foo
|
||||||
|
`,
|
||||||
|
filter: namespace.Filter{Namespace: "foo"},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "add-recurse",
|
name: "add-recurse",
|
||||||
input: `
|
input: `
|
||||||
@@ -163,47 +194,47 @@ metadata:
|
|||||||
{
|
{
|
||||||
name: "update-clusterrolebinding",
|
name: "update-clusterrolebinding",
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: default
|
- name: default
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: default
|
- name: default
|
||||||
namespace: foo
|
namespace: foo
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: something
|
- name: something
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: something
|
- name: something
|
||||||
namespace: foo
|
namespace: foo
|
||||||
`,
|
`,
|
||||||
expected: `
|
expected: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: default
|
- name: default
|
||||||
namespace: bar
|
namespace: bar
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: default
|
- name: default
|
||||||
namespace: bar
|
namespace: bar
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: something
|
- name: something
|
||||||
---
|
---
|
||||||
apiVersion: example.com/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
subjects:
|
subjects:
|
||||||
- name: something
|
- name: something
|
||||||
|
|||||||
6
api/filters/patchjson6902/doc.go
Normal file
6
api/filters/patchjson6902/doc.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package namespace contains a kio.Filter implementation of the kustomize
|
||||||
|
// patchjson6902 transformer
|
||||||
|
package patchjson6902
|
||||||
55
api/filters/patchjson6902/example_test.go
Normal file
55
api/filters/patchjson6902/example_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package patchjson6902
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Bar
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
namespace: bar
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{
|
||||||
|
Filter{
|
||||||
|
Patch: `
|
||||||
|
- op: replace
|
||||||
|
path: /metadata/namespace
|
||||||
|
value: "ns"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// namespace: ns
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Bar
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// namespace: ns
|
||||||
|
}
|
||||||
65
api/filters/patchjson6902/patchjson6902.go
Normal file
65
api/filters/patchjson6902/patchjson6902.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package patchjson6902
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
k8syaml "sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Patch string
|
||||||
|
|
||||||
|
decodedPatch jsonpatch.Patch
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
|
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
decodedPatch, err := pf.decodePatch()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pf.decodedPatch = decodedPatch
|
||||||
|
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pf Filter) decodePatch() (jsonpatch.Patch, error) {
|
||||||
|
patch := pf.Patch
|
||||||
|
// If the patch doesn't look like a JSON6902 patch, we
|
||||||
|
// try to parse it to json.
|
||||||
|
if !strings.HasPrefix(pf.Patch, "[") {
|
||||||
|
p, err := k8syaml.YAMLToJSON([]byte(patch))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
patch = string(p)
|
||||||
|
}
|
||||||
|
decodedPatch, err := jsonpatch.DecodePatch([]byte(patch))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return decodedPatch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
// We don't actually use the kyaml library for manipulating the
|
||||||
|
// yaml here. We just marshal it to json and rely on the
|
||||||
|
// jsonpatch library to take care of applying the patch.
|
||||||
|
// This means ordering might not be preserved with this filter.
|
||||||
|
b, err := node.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res, err := pf.decodedPatch.Apply(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = node.UnmarshalJSON(res)
|
||||||
|
return node, err
|
||||||
|
}
|
||||||
173
api/filters/patchjson6902/patchjson6902_test.go
Normal file
173
api/filters/patchjson6902/patchjson6902_test.go
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package patchjson6902
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const input = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestSomething(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
testName string
|
||||||
|
input string
|
||||||
|
filter Filter
|
||||||
|
expectedOutput string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testName: "single operation, json",
|
||||||
|
input: input,
|
||||||
|
filter: Filter{
|
||||||
|
Patch: `[
|
||||||
|
{"op": "replace", "path": "/spec/replica", "value": 5}
|
||||||
|
]`,
|
||||||
|
},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 5
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "multiple operations, json",
|
||||||
|
input: input,
|
||||||
|
filter: Filter{
|
||||||
|
Patch: `[
|
||||||
|
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||||
|
{"op": "add", "path": "/spec/replica", "value": 999},
|
||||||
|
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||||
|
]`,
|
||||||
|
},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 999
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- arg1
|
||||||
|
- arg2
|
||||||
|
- arg3
|
||||||
|
image: nginx
|
||||||
|
name: my-nginx
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "single operation, yaml",
|
||||||
|
input: input,
|
||||||
|
filter: Filter{
|
||||||
|
Patch: `
|
||||||
|
- op: replace
|
||||||
|
path: /spec/replica
|
||||||
|
value: 5
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 5
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "multiple operations, yaml",
|
||||||
|
input: input,
|
||||||
|
filter: Filter{
|
||||||
|
Patch: `
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/name
|
||||||
|
value: my-nginx
|
||||||
|
- op: add
|
||||||
|
path: /spec/replica
|
||||||
|
value: 999
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/command
|
||||||
|
value:
|
||||||
|
- arg1
|
||||||
|
- arg2
|
||||||
|
- arg3
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 999
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- arg1
|
||||||
|
- arg2
|
||||||
|
- arg3
|
||||||
|
image: nginx
|
||||||
|
name: my-nginx
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.testName, func(t *testing.T) {
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expectedOutput),
|
||||||
|
strings.TrimSpace(
|
||||||
|
filtertest.RunFilter(t, tc.input, tc.filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
6
api/filters/patchstrategicmerge/doc.go
Normal file
6
api/filters/patchstrategicmerge/doc.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package patchstrategicmerge contains a kio.Filter implementation of the
|
||||||
|
// kustomize strategic merge patch transformer.
|
||||||
|
package patchstrategicmerge
|
||||||
49
api/filters/patchstrategicmerge/example_test.go
Normal file
49
api/filters/patchstrategicmerge/example_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package patchstrategicmerge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
err := kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{Filter{
|
||||||
|
Patch: yaml.MustParse(`
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
`),
|
||||||
|
}},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// replicas: 3
|
||||||
|
// template:
|
||||||
|
// containers:
|
||||||
|
// - image: nginx
|
||||||
|
}
|
||||||
36
api/filters/patchstrategicmerge/patchstrategicmerge.go
Normal file
36
api/filters/patchstrategicmerge/patchstrategicmerge.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package patchstrategicmerge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Patch *yaml.RNode
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
|
// Filter does a strategic merge patch, which can delete nodes.
|
||||||
|
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
var result []*yaml.RNode
|
||||||
|
for i := range nodes {
|
||||||
|
r, err := merge2.Merge(
|
||||||
|
pf.Patch, nodes[i],
|
||||||
|
yaml.MergeOptions{
|
||||||
|
ListIncreaseDirection: yaml.MergeOptionsListPrepend,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
749
api/filters/patchstrategicmerge/patchstrategicmerge_test.go
Normal file
749
api/filters/patchstrategicmerge/patchstrategicmerge_test.go
Normal file
@@ -0,0 +1,749 @@
|
|||||||
|
package patchstrategicmerge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
patch *yaml.RNode
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
"simple": {
|
||||||
|
input: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: clown
|
||||||
|
spec:
|
||||||
|
numReplicas: 1
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: clown
|
||||||
|
spec:
|
||||||
|
numReplicas: 999
|
||||||
|
`),
|
||||||
|
expected: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: clown
|
||||||
|
spec:
|
||||||
|
numReplicas: 999
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"nullMapEntry1": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
B:
|
||||||
|
C: Z
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
C: Z
|
||||||
|
D: W
|
||||||
|
baz:
|
||||||
|
hello: world
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
C: Z
|
||||||
|
D: W
|
||||||
|
baz:
|
||||||
|
hello: world
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"nullMapEntry2": {
|
||||||
|
input: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
C: Z
|
||||||
|
D: W
|
||||||
|
baz:
|
||||||
|
hello: world
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
B:
|
||||||
|
C: Z
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo
|
||||||
|
metadata:
|
||||||
|
name: my-foo
|
||||||
|
spec:
|
||||||
|
bar:
|
||||||
|
C: Z
|
||||||
|
D: W
|
||||||
|
baz:
|
||||||
|
hello: world
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"simple patch": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
metadata:
|
||||||
|
name: yourDeploy
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: yourDeploy
|
||||||
|
kind: Deployment
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"container patch": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: foo1
|
||||||
|
- name: foo2
|
||||||
|
- name: foo3
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: foo0
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: foo0
|
||||||
|
- name: foo1
|
||||||
|
- name: foo2
|
||||||
|
- name: foo3
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"volumes patch": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: foo1
|
||||||
|
- name: foo2
|
||||||
|
- name: foo3
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: foo0
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: foo0
|
||||||
|
- name: foo1
|
||||||
|
- name: foo2
|
||||||
|
- name: foo3
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"nested patch": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
args:
|
||||||
|
- abc
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
args:
|
||||||
|
- def
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
args:
|
||||||
|
- def
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"remove mapping - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
$patch: delete
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers: []
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"replace mapping - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
$patch: replace
|
||||||
|
containers:
|
||||||
|
- name: new
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: new
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"merge mapping - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test1
|
||||||
|
$patch: merge
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test1
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"remove list - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- whatever
|
||||||
|
- $patch: delete
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec: {}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"replace list - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: replace
|
||||||
|
image: replace
|
||||||
|
- $patch: replace
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: replace
|
||||||
|
image: replace
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"merge list - directive": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test2
|
||||||
|
image: test2
|
||||||
|
- $patch: merge
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: test2
|
||||||
|
image: test2
|
||||||
|
- name: test
|
||||||
|
image: test
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"list map keys - add a port, no names": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 80
|
||||||
|
protocol: UDP
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 80
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"list map keys - add name to port": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
name: UDP-name-patch
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
name: UDP-name-patch
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"list map keys - replace port name": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
name: UDP-name-original
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
name: TCP-name-original
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
name: UDP-name-patch
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: UDP
|
||||||
|
name: UDP-name-patch
|
||||||
|
- containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
name: TCP-name-original
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"list map keys - add a port, no protocol": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: test-image
|
||||||
|
name: test-deployment
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
- containerPort: 8080
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Test for issue #3513
|
||||||
|
// Currently broken; when one port has only containerPort, the output
|
||||||
|
// should not merge containerPort 8301 together
|
||||||
|
// This occurs because when protocol is missing on the first port,
|
||||||
|
// the merge code uses [containerPort] as the merge key rather than
|
||||||
|
// [containerPort, protocol]
|
||||||
|
"list map keys - protocol only present on some ports": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: consul
|
||||||
|
image: "dashicorp/consul:1.9.1"
|
||||||
|
ports:
|
||||||
|
- containerPort: 8500
|
||||||
|
name: http
|
||||||
|
- containerPort: 8301
|
||||||
|
protocol: "TCP"
|
||||||
|
- containerPort: 8301
|
||||||
|
protocol: "UDP"
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
labels:
|
||||||
|
test: label
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: test-deployment
|
||||||
|
labels:
|
||||||
|
test: label
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: consul
|
||||||
|
image: "dashicorp/consul:1.9.1"
|
||||||
|
ports:
|
||||||
|
- containerPort: 8500
|
||||||
|
name: http
|
||||||
|
- containerPort: 8301
|
||||||
|
protocol: "TCP"
|
||||||
|
- containerPort: 8301
|
||||||
|
protocol: "UDP"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
f := Filter{
|
||||||
|
Patch: tc.patch,
|
||||||
|
}
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expected),
|
||||||
|
strings.TrimSpace(
|
||||||
|
filtertest.RunFilter(t, tc.input, f))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,12 +9,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleFilter() {
|
func ExampleFilter() {
|
||||||
fss := builtinconfig.MakeDefaultConfig().NamePrefix
|
|
||||||
err := kio.Pipeline{
|
err := kio.Pipeline{
|
||||||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
@@ -27,7 +26,8 @@ kind: Bar
|
|||||||
metadata:
|
metadata:
|
||||||
name: instance
|
name: instance
|
||||||
`)}},
|
`)}},
|
||||||
Filters: []kio.Filter{prefixsuffix.Filter{Prefix: "baz-", FsSlice: fss}},
|
Filters: []kio.Filter{prefixsuffix.Filter{
|
||||||
|
Prefix: "baz-", FieldSpec: types.FieldSpec{Path: "metadata/name"}}},
|
||||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
}.Execute()
|
}.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ package prefixsuffix
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
@@ -17,27 +18,26 @@ type Filter struct {
|
|||||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||||
|
|
||||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the filter on a single node rather than a slice
|
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
err := node.PipeE(fieldspec.Filter{
|
||||||
// transformations based on data -- :)
|
FieldSpec: f.FieldSpec,
|
||||||
err := node.PipeE(fsslice.Filter{
|
SetValue: f.evaluateField,
|
||||||
FsSlice: ns.FsSlice,
|
|
||||||
SetValue: ns.set,
|
|
||||||
CreateKind: yaml.ScalarNode, // Name is a ScalarNode
|
CreateKind: yaml.ScalarNode, // Name is a ScalarNode
|
||||||
|
CreateTag: yaml.NodeTagString,
|
||||||
})
|
})
|
||||||
return node, err
|
return node, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns Filter) set(node *yaml.RNode) error {
|
func (f Filter) evaluateField(node *yaml.RNode) error {
|
||||||
return fsslice.SetScalar(fmt.Sprintf(
|
return filtersutil.SetScalar(fmt.Sprintf(
|
||||||
"%s%s%s", ns.Prefix, node.YNode().Value, ns.Suffix))(node)
|
"%s%s%s", f.Prefix, node.YNode().Value, f.Suffix))(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
|
||||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tests = []TestCase{
|
var tests = map[string]TestCase{
|
||||||
{
|
"prefix": {
|
||||||
name: "prefix",
|
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
@@ -40,10 +38,10 @@ metadata:
|
|||||||
name: foo-instance
|
name: foo-instance
|
||||||
`,
|
`,
|
||||||
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
||||||
|
fs: types.FieldSpec{Path: "metadata/name"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
"suffix": {
|
||||||
name: "suffix",
|
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
@@ -67,10 +65,10 @@ metadata:
|
|||||||
name: instance-foo
|
name: instance-foo
|
||||||
`,
|
`,
|
||||||
filter: prefixsuffix.Filter{Suffix: "-foo"},
|
filter: prefixsuffix.Filter{Suffix: "-foo"},
|
||||||
|
fs: types.FieldSpec{Path: "metadata/name"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
"prefix-suffix": {
|
||||||
name: "prefix-suffix",
|
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
@@ -94,10 +92,10 @@ metadata:
|
|||||||
name: bar-instance-foo
|
name: bar-instance-foo
|
||||||
`,
|
`,
|
||||||
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
|
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
|
||||||
|
fs: types.FieldSpec{Path: "metadata/name"},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
"data-fieldspecs": {
|
||||||
name: "data-fieldspecs",
|
|
||||||
input: `
|
input: `
|
||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
@@ -119,7 +117,7 @@ a:
|
|||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Foo
|
kind: Foo
|
||||||
metadata:
|
metadata:
|
||||||
name: foo-instance
|
name: instance
|
||||||
a:
|
a:
|
||||||
b:
|
b:
|
||||||
c: foo-d
|
c: foo-d
|
||||||
@@ -127,35 +125,28 @@ a:
|
|||||||
apiVersion: example.com/v1
|
apiVersion: example.com/v1
|
||||||
kind: Bar
|
kind: Bar
|
||||||
metadata:
|
metadata:
|
||||||
name: foo-instance
|
name: instance
|
||||||
a:
|
a:
|
||||||
b:
|
b:
|
||||||
c: foo-d
|
c: foo-d
|
||||||
`,
|
`,
|
||||||
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
filter: prefixsuffix.Filter{Prefix: "foo-"},
|
||||||
fsslice: []types.FieldSpec{
|
fs: types.FieldSpec{Path: "a/b/c"},
|
||||||
{
|
|
||||||
Path: "a/b/c",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
name string
|
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter prefixsuffix.Filter
|
filter prefixsuffix.Filter
|
||||||
fsslice types.FsSlice
|
fs types.FieldSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = builtinconfig.MakeDefaultConfig()
|
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
for i := range tests {
|
for name := range tests {
|
||||||
test := tests[i]
|
test := tests[name]
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
test.filter.FsSlice = append(config.NamePrefix, test.fsslice...)
|
test.filter.FieldSpec = test.fs
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(test.expected),
|
strings.TrimSpace(test.expected),
|
||||||
strings.TrimSpace(
|
strings.TrimSpace(
|
||||||
|
|||||||
3
api/filters/refvar/doc.go
Normal file
3
api/filters/refvar/doc.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// Package refvar contains a kio.Filter implementation of the kustomize
|
||||||
|
// refvar transformer (find and replace $(FOO) style variables in strings).
|
||||||
|
package refvar
|
||||||
147
api/filters/refvar/expand.go
Normal file
147
api/filters/refvar/expand.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package refvar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
operator = '$'
|
||||||
|
referenceOpener = '('
|
||||||
|
referenceCloser = ')'
|
||||||
|
)
|
||||||
|
|
||||||
|
// syntaxWrap returns the input string wrapped by the expansion syntax.
|
||||||
|
func syntaxWrap(input string) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteByte(operator)
|
||||||
|
sb.WriteByte(referenceOpener)
|
||||||
|
sb.WriteString(input)
|
||||||
|
sb.WriteByte(referenceCloser)
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MappingFunc maps a string to anything.
|
||||||
|
type MappingFunc func(string) interface{}
|
||||||
|
|
||||||
|
// MakePrimitiveReplacer returns a MappingFunc that uses a map to do
|
||||||
|
// replacements, and a histogram to count map hits.
|
||||||
|
//
|
||||||
|
// Func behavior:
|
||||||
|
//
|
||||||
|
// If the input key is NOT found in the map, the key is wrapped up as
|
||||||
|
// as a variable declaration string and returned, e.g. key FOO becomes $(FOO).
|
||||||
|
// This string is presumably put back where it was found, and might get replaced
|
||||||
|
// later.
|
||||||
|
//
|
||||||
|
// If the key is found in the map, the value is returned if it is a primitive
|
||||||
|
// type (string, bool, number), and the hit is counted.
|
||||||
|
//
|
||||||
|
// If it's not a primitive type (e.g. a map, struct, func, etc.) then this
|
||||||
|
// function doesn't know what to do with it and it returns the key wrapped up
|
||||||
|
// again as if it had not been replaced. This should probably be an error.
|
||||||
|
func MakePrimitiveReplacer(
|
||||||
|
counts map[string]int, someMap map[string]interface{}) MappingFunc {
|
||||||
|
return func(key string) interface{} {
|
||||||
|
if value, ok := someMap[key]; ok {
|
||||||
|
switch typedV := value.(type) {
|
||||||
|
case string, int, int32, int64, float32, float64, bool:
|
||||||
|
counts[key]++
|
||||||
|
return typedV
|
||||||
|
default:
|
||||||
|
// If the value is some complicated type (e.g. a map or struct),
|
||||||
|
// this function doesn't know how to jam it into a string,
|
||||||
|
// so just pretend it was a cache miss.
|
||||||
|
// Likely this should be an error instead of a silent failure,
|
||||||
|
// since the programmer passed an impossible value.
|
||||||
|
log.Printf(
|
||||||
|
"MakePrimitiveReplacer: bad replacement type=%T val=%v",
|
||||||
|
typedV, typedV)
|
||||||
|
return syntaxWrap(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If unable to return the mapped variable, return it
|
||||||
|
// as it was found, and a later mapping might be able to
|
||||||
|
// replace it.
|
||||||
|
return syntaxWrap(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoReplacements replaces variable references in the input string
|
||||||
|
// using the mapping function.
|
||||||
|
func DoReplacements(input string, mapping MappingFunc) interface{} {
|
||||||
|
var buf strings.Builder
|
||||||
|
checkpoint := 0
|
||||||
|
for cursor := 0; cursor < len(input); cursor++ {
|
||||||
|
if input[cursor] == operator && cursor+1 < len(input) {
|
||||||
|
// Copy the portion of the input string since the last
|
||||||
|
// checkpoint into the buffer
|
||||||
|
buf.WriteString(input[checkpoint:cursor])
|
||||||
|
|
||||||
|
// Attempt to read the variable name as defined by the
|
||||||
|
// syntax from the input string
|
||||||
|
read, isVar, advance := tryReadVariableName(input[cursor+1:])
|
||||||
|
|
||||||
|
if isVar {
|
||||||
|
// We were able to read a variable name correctly;
|
||||||
|
// apply the mapping to the variable name and copy the
|
||||||
|
// bytes into the buffer
|
||||||
|
mapped := mapping(read)
|
||||||
|
if input == syntaxWrap(read) {
|
||||||
|
// Preserve the type of variable
|
||||||
|
return mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable is used in a middle of a string
|
||||||
|
buf.WriteString(fmt.Sprintf("%v", mapped))
|
||||||
|
} else {
|
||||||
|
// Not a variable name; copy the read bytes into the buffer
|
||||||
|
buf.WriteString(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance the cursor in the input string to account for
|
||||||
|
// bytes consumed to read the variable name expression
|
||||||
|
cursor += advance
|
||||||
|
|
||||||
|
// Advance the checkpoint in the input string
|
||||||
|
checkpoint = cursor + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the buffer and any remaining unwritten bytes in the
|
||||||
|
// input string.
|
||||||
|
return buf.String() + input[checkpoint:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryReadVariableName attempts to read a variable name from the input
|
||||||
|
// string and returns the content read from the input, whether that content
|
||||||
|
// represents a variable name to perform mapping on, and the number of bytes
|
||||||
|
// consumed in the input string.
|
||||||
|
//
|
||||||
|
// The input string is assumed not to contain the initial operator.
|
||||||
|
func tryReadVariableName(input string) (string, bool, int) {
|
||||||
|
switch input[0] {
|
||||||
|
case operator:
|
||||||
|
// Escaped operator; return it.
|
||||||
|
return input[0:1], false, 1
|
||||||
|
case referenceOpener:
|
||||||
|
// Scan to expression closer
|
||||||
|
for i := 1; i < len(input); i++ {
|
||||||
|
if input[i] == referenceCloser {
|
||||||
|
return input[1:i], true, i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incomplete reference; return it.
|
||||||
|
return string(operator) + string(referenceOpener), false, 1
|
||||||
|
default:
|
||||||
|
// Not the beginning of an expression, ie, an operator
|
||||||
|
// that doesn't begin an expression. Return the operator
|
||||||
|
// and the first rune in the string.
|
||||||
|
return string(operator) + string(input[0]), false, 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package expansion_test
|
package refvar_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
|
"github.com/stretchr/testify/assert"
|
||||||
|
. "sigs.k8s.io/kustomize/api/filters/refvar"
|
||||||
)
|
)
|
||||||
|
|
||||||
type expected struct {
|
type expected struct {
|
||||||
@@ -15,6 +16,48 @@ type expected struct {
|
|||||||
edited string
|
edited string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrimitiveReplacer(t *testing.T) {
|
||||||
|
varCounts := make(map[string]int)
|
||||||
|
f := MakePrimitiveReplacer(
|
||||||
|
varCounts,
|
||||||
|
map[string]interface{}{
|
||||||
|
"FOO": "bar",
|
||||||
|
"ZOO": "$(FOO)-1",
|
||||||
|
"BLU": "$(ZOO)-2",
|
||||||
|
"EIGHT": 8,
|
||||||
|
"PI": 3.14159,
|
||||||
|
"ZINT": "$(INT)",
|
||||||
|
"BOOL": "true",
|
||||||
|
"HUGENUMBER": int64(9223372036854775807),
|
||||||
|
"CRAZYMAP": map[string]int{"crazy": 200},
|
||||||
|
"ZBOOL": "$(BOOL)",
|
||||||
|
})
|
||||||
|
assert.Equal(t, "$()", f(""))
|
||||||
|
assert.Equal(t, "$( )", f(" "))
|
||||||
|
assert.Equal(t, "$(florida)", f("florida"))
|
||||||
|
assert.Equal(t, "$(0)", f("0"))
|
||||||
|
assert.Equal(t, "bar", f("FOO"))
|
||||||
|
assert.Equal(t, "bar", f("FOO"))
|
||||||
|
assert.Equal(t, "bar", f("FOO"))
|
||||||
|
assert.Equal(t, 8, f("EIGHT"))
|
||||||
|
assert.Equal(t, 8, f("EIGHT"))
|
||||||
|
assert.Equal(t, 3.14159, f("PI"))
|
||||||
|
assert.Equal(t, "true", f("BOOL"))
|
||||||
|
assert.Equal(t, int64(9223372036854775807), f("HUGENUMBER"))
|
||||||
|
assert.Equal(t, "$(FOO)-1", f("ZOO"))
|
||||||
|
assert.Equal(t, "$(CRAZYMAP)", f("CRAZYMAP"))
|
||||||
|
assert.Equal(t,
|
||||||
|
map[string]int{
|
||||||
|
"FOO": 3,
|
||||||
|
"EIGHT": 2,
|
||||||
|
"BOOL": 1,
|
||||||
|
"PI": 1,
|
||||||
|
"ZOO": 1,
|
||||||
|
"HUGENUMBER": 1,
|
||||||
|
},
|
||||||
|
varCounts)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMapReference(t *testing.T) {
|
func TestMapReference(t *testing.T) {
|
||||||
type env struct {
|
type env struct {
|
||||||
Name string
|
Name string
|
||||||
@@ -51,7 +94,7 @@ func TestMapReference(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
declaredEnv := map[string]interface{}{
|
varMap := map[string]interface{}{
|
||||||
"FOO": "bar",
|
"FOO": "bar",
|
||||||
"ZOO": "$(FOO)-1",
|
"ZOO": "$(FOO)-1",
|
||||||
"BLU": "$(ZOO)-2",
|
"BLU": "$(ZOO)-2",
|
||||||
@@ -61,11 +104,11 @@ func TestMapReference(t *testing.T) {
|
|||||||
"ZBOOL": "$(BOOL)",
|
"ZBOOL": "$(BOOL)",
|
||||||
}
|
}
|
||||||
|
|
||||||
counts := make(map[string]int)
|
varCounts := make(map[string]int)
|
||||||
mapping := MappingFuncFor(counts, declaredEnv)
|
|
||||||
|
|
||||||
for _, env := range envs {
|
for _, env := range envs {
|
||||||
declaredEnv[env.Name] = Expand(fmt.Sprintf("%v", env.Value), mapping)
|
varMap[env.Name] = DoReplacements(
|
||||||
|
fmt.Sprintf("%v", env.Value),
|
||||||
|
MakePrimitiveReplacer(varCounts, varMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedEnv := map[string]expected{
|
expectedEnv := map[string]expected{
|
||||||
@@ -79,45 +122,20 @@ func TestMapReference(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range expectedEnv {
|
for k, v := range expectedEnv {
|
||||||
if e, a := v, declaredEnv[k]; e.edited != a || e.count != counts[k] {
|
if e, a := v, varMap[k]; e.edited != a || e.count != varCounts[k] {
|
||||||
t.Errorf("Expected %v count=%d, got %v count=%d",
|
t.Errorf("Expected %v count=%d, got %v count=%d",
|
||||||
e.edited, e.count, a, counts[k])
|
e.edited, e.count, a, varCounts[k])
|
||||||
} else {
|
} else {
|
||||||
delete(declaredEnv, k)
|
delete(varMap, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(declaredEnv) != 0 {
|
if len(varMap) != 0 {
|
||||||
t.Errorf("Unexpected keys in declared env: %v", declaredEnv)
|
t.Errorf("Unexpected keys in declared env: %v", varMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapping(t *testing.T) {
|
func TestMapping(t *testing.T) {
|
||||||
context := map[string]interface{}{
|
|
||||||
"VAR_A": "A",
|
|
||||||
"VAR_B": "B",
|
|
||||||
"VAR_C": "C",
|
|
||||||
"VAR_REF": "$(VAR_A)",
|
|
||||||
"VAR_EMPTY": "",
|
|
||||||
}
|
|
||||||
doExpansionTest(t, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMappingDual(t *testing.T) {
|
|
||||||
context := map[string]interface{}{
|
|
||||||
"VAR_A": "A",
|
|
||||||
"VAR_EMPTY": "",
|
|
||||||
}
|
|
||||||
context2 := map[string]interface{}{
|
|
||||||
"VAR_B": "B",
|
|
||||||
"VAR_C": "C",
|
|
||||||
"VAR_REF": "$(VAR_A)",
|
|
||||||
}
|
|
||||||
|
|
||||||
doExpansionTest(t, context, context2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doExpansionTest(t *testing.T, context ...map[string]interface{}) {
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
@@ -333,11 +351,17 @@ func doExpansionTest(t *testing.T, context ...map[string]interface{}) {
|
|||||||
expected: "\n",
|
expected: "\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
counts := make(map[string]int)
|
counts := make(map[string]int)
|
||||||
mapping := MappingFuncFor(counts, context...)
|
expanded := DoReplacements(
|
||||||
expanded := Expand(fmt.Sprintf("%v", tc.input), mapping)
|
fmt.Sprintf("%v", tc.input),
|
||||||
|
MakePrimitiveReplacer(counts, map[string]interface{}{
|
||||||
|
"VAR_A": "A",
|
||||||
|
"VAR_B": "B",
|
||||||
|
"VAR_C": "C",
|
||||||
|
"VAR_REF": "$(VAR_A)",
|
||||||
|
"VAR_EMPTY": "",
|
||||||
|
}))
|
||||||
if e, a := tc.expected, expanded; e != a {
|
if e, a := tc.expected, expanded; e != a {
|
||||||
t.Errorf("%v: expected %q, got %q", tc.name, e, a)
|
t.Errorf("%v: expected %q, got %q", tc.name, e, a)
|
||||||
}
|
}
|
||||||
@@ -347,8 +371,7 @@ func doExpansionTest(t *testing.T, context ...map[string]interface{}) {
|
|||||||
}
|
}
|
||||||
if len(tc.counts) > 0 {
|
if len(tc.counts) > 0 {
|
||||||
for k, expectedCount := range tc.counts {
|
for k, expectedCount := range tc.counts {
|
||||||
c, ok := counts[k]
|
if c, ok := counts[k]; ok {
|
||||||
if ok {
|
|
||||||
if c != expectedCount {
|
if c != expectedCount {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"%v: k=%s, expected count %d, got %d",
|
"%v: k=%s, expected count %d, got %d",
|
||||||
110
api/filters/refvar/refvar.go
Normal file
110
api/filters/refvar/refvar.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package refvar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter updates $(VAR) style variables with values.
|
||||||
|
// The fieldSpecs are the places to look for occurrences of $(VAR).
|
||||||
|
type Filter struct {
|
||||||
|
MappingFunc MappingFunc `json:"mappingFunc,omitempty" yaml:"mappingFunc,omitempty"`
|
||||||
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
err := node.PipeE(fieldspec.Filter{
|
||||||
|
FieldSpec: f.FieldSpec,
|
||||||
|
SetValue: f.set,
|
||||||
|
})
|
||||||
|
return node, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) set(node *yaml.RNode) error {
|
||||||
|
if yaml.IsMissingOrNull(node) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch node.YNode().Kind {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
return f.setScalar(node)
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return f.setMap(node)
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return f.setSeq(node)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid type encountered %v", node.YNode().Kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNodeValue(node *yaml.Node, newValue interface{}) {
|
||||||
|
switch newValue := newValue.(type) {
|
||||||
|
case int:
|
||||||
|
node.Value = strconv.FormatInt(int64(newValue), 10)
|
||||||
|
node.Tag = yaml.NodeTagInt
|
||||||
|
case int32:
|
||||||
|
node.Value = strconv.FormatInt(int64(newValue), 10)
|
||||||
|
node.Tag = yaml.NodeTagInt
|
||||||
|
case int64:
|
||||||
|
node.Value = strconv.FormatInt(newValue, 10)
|
||||||
|
node.Tag = yaml.NodeTagInt
|
||||||
|
case bool:
|
||||||
|
node.SetString(strconv.FormatBool(newValue))
|
||||||
|
node.Tag = yaml.NodeTagBool
|
||||||
|
case float32:
|
||||||
|
node.SetString(strconv.FormatFloat(float64(newValue), 'f', -1, 32))
|
||||||
|
node.Tag = yaml.NodeTagFloat
|
||||||
|
case float64:
|
||||||
|
node.SetString(strconv.FormatFloat(newValue, 'f', -1, 64))
|
||||||
|
node.Tag = yaml.NodeTagFloat
|
||||||
|
default:
|
||||||
|
node.SetString(newValue.(string))
|
||||||
|
node.Tag = yaml.NodeTagString
|
||||||
|
}
|
||||||
|
node.Style = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) setScalar(node *yaml.RNode) error {
|
||||||
|
if !yaml.IsYNodeString(node.YNode()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := DoReplacements(node.YNode().Value, f.MappingFunc)
|
||||||
|
updateNodeValue(node.YNode(), v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) setMap(node *yaml.RNode) error {
|
||||||
|
contents := node.YNode().Content
|
||||||
|
for i := 0; i < len(contents); i += 2 {
|
||||||
|
if !yaml.IsYNodeString(contents[i]) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"invalid map key: value='%s', tag='%s'",
|
||||||
|
contents[i].Value, contents[i].Tag)
|
||||||
|
}
|
||||||
|
if !yaml.IsYNodeString(contents[i+1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newValue := DoReplacements(contents[i+1].Value, f.MappingFunc)
|
||||||
|
updateNodeValue(contents[i+1], newValue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Filter) setSeq(node *yaml.RNode) error {
|
||||||
|
for _, item := range node.YNode().Content {
|
||||||
|
if !yaml.IsYNodeString(item) {
|
||||||
|
return fmt.Errorf("invalid value type expect a string")
|
||||||
|
}
|
||||||
|
newValue := DoReplacements(item.Value, f.MappingFunc)
|
||||||
|
updateNodeValue(item, newValue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
301
api/filters/refvar/refvar_test.go
Normal file
301
api/filters/refvar/refvar_test.go
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
package refvar_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
. "sigs.k8s.io/kustomize/api/filters/refvar"
|
||||||
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var makeMf = func(theMap map[string]interface{}) MappingFunc {
|
||||||
|
ignored := make(map[string]int)
|
||||||
|
return MakePrimitiveReplacer(ignored, theMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
filter Filter
|
||||||
|
}{
|
||||||
|
"simple scalar": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: $(VAR)`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 5`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"VAR": int64(5),
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"non-string scalar": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 1`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 1`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"VAR": int64(5),
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"wrong path": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 1`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
spec:
|
||||||
|
replicas: 1`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"VAR": int64(5),
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "a/b/c"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sequence": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
- $(FOO)
|
||||||
|
- $(BAR)
|
||||||
|
- $(BAZ)
|
||||||
|
- $(FOO)+$(BAR)
|
||||||
|
- $(BOOL)
|
||||||
|
- $(FLOAT)`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
- foo
|
||||||
|
- bar
|
||||||
|
- $(BAZ)
|
||||||
|
- foo+bar
|
||||||
|
- false
|
||||||
|
- 1.23`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"FOO": "foo",
|
||||||
|
"BAR": "bar",
|
||||||
|
"BOOL": false,
|
||||||
|
"FLOAT": 1.23,
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"maps": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
FOO: $(FOO)
|
||||||
|
BAR: $(BAR)
|
||||||
|
BAZ: $(BAZ)
|
||||||
|
PLUS: $(FOO)+$(BAR)`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
FOO: foo
|
||||||
|
BAR: bar
|
||||||
|
BAZ: $(BAZ)
|
||||||
|
PLUS: foo+bar`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"FOO": "foo",
|
||||||
|
"BAR": "bar",
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"complicated case": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
slice1:
|
||||||
|
- $(FOO)
|
||||||
|
slice2:
|
||||||
|
FOO: $(FOO)
|
||||||
|
BAR: $(BAR)
|
||||||
|
BOOL: false
|
||||||
|
INT: 0
|
||||||
|
SLICE:
|
||||||
|
- $(FOO)`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
slice1:
|
||||||
|
- $(FOO)
|
||||||
|
slice2:
|
||||||
|
FOO: foo
|
||||||
|
BAR: bar
|
||||||
|
BOOL: false
|
||||||
|
INT: 0
|
||||||
|
SLICE:
|
||||||
|
- $(FOO)`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"FOO": "foo",
|
||||||
|
"BAR": "bar",
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data/slice2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"null value": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
FOO: null`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
FOO: null`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
// no replacements!
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data/FOO"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expected),
|
||||||
|
strings.TrimSpace(
|
||||||
|
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterUnhappy(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expectedError string
|
||||||
|
filter Filter
|
||||||
|
}{
|
||||||
|
"non-string in sequence": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
slice:
|
||||||
|
- false`,
|
||||||
|
expectedError: `considering field 'data/slice' of object
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
annotations:
|
||||||
|
config.kubernetes.io/index: '0'
|
||||||
|
internal.config.kubernetes.io/index: '0'
|
||||||
|
data:
|
||||||
|
slice:
|
||||||
|
- false
|
||||||
|
: invalid value type expect a string`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"VAR": int64(5),
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data/slice"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid key in map": {
|
||||||
|
input: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
data:
|
||||||
|
1: str`,
|
||||||
|
expectedError: `considering field 'data' of object
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dep
|
||||||
|
annotations:
|
||||||
|
config.kubernetes.io/index: '0'
|
||||||
|
internal.config.kubernetes.io/index: '0'
|
||||||
|
data:
|
||||||
|
1: str
|
||||||
|
: invalid map key: value='1', tag='` + yaml.NodeTagInt + `'`,
|
||||||
|
filter: Filter{
|
||||||
|
MappingFunc: makeMf(map[string]interface{}{
|
||||||
|
"VAR": int64(5),
|
||||||
|
}),
|
||||||
|
FieldSpec: types.FieldSpec{Path: "data"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
_, err := filtertest_test.RunFilterE(t, tc.input, tc.filter)
|
||||||
|
if !assert.EqualError(t, err, tc.expectedError) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
4
api/filters/replacement/doc.go
Normal file
4
api/filters/replacement/doc.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// Package replacement contains a kio.Filter implementation of the kustomize
|
||||||
|
// replacement transformer (accepts sources and looks for targets to replace
|
||||||
|
// their values with values from the sources).
|
||||||
|
package replacement
|
||||||
68
api/filters/replacement/example_test.go
Normal file
68
api/filters/replacement/example_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package replacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
f := Filter{}
|
||||||
|
err := yaml.Unmarshal([]byte(`
|
||||||
|
replacements:
|
||||||
|
- source:
|
||||||
|
kind: Foo2
|
||||||
|
fieldPath: spec.replicas
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Foo1
|
||||||
|
fieldPaths:
|
||||||
|
- spec.replicas`), &f)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo1
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo2
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
replicas: 99
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{f},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo1
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// replicas: 99
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo2
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// replicas: 99
|
||||||
|
}
|
||||||
221
api/filters/replacement/replacement.go
Normal file
221
api/filters/replacement/replacement.go
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package replacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||||
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Replacements []types.Replacement `json:"replacements,omitempty" yaml:"replacements,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter replaces values of targets with values from sources
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
for _, r := range f.Replacements {
|
||||||
|
if r.Source == nil || r.Targets == nil {
|
||||||
|
return nil, fmt.Errorf("replacements must specify a source and at least one target")
|
||||||
|
}
|
||||||
|
value, err := getReplacement(nodes, &r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nodes, err = applyReplacement(nodes, value, r.Targets)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.TargetSelector) ([]*yaml.RNode, error) {
|
||||||
|
for _, t := range targets {
|
||||||
|
if t.Select == nil {
|
||||||
|
return nil, fmt.Errorf("target must specify resources to select")
|
||||||
|
}
|
||||||
|
if len(t.FieldPaths) == 0 {
|
||||||
|
t.FieldPaths = []string{types.DefaultReplacementFieldPath}
|
||||||
|
}
|
||||||
|
for _, n := range nodes {
|
||||||
|
ids, err := utils.MakeResIds(n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter targets by label and annotation selectors
|
||||||
|
selectByAnnoAndLabel, err := selectByAnnoAndLabel(n, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !selectByAnnoAndLabel {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter targets by matching resource IDs
|
||||||
|
for _, id := range ids {
|
||||||
|
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) {
|
||||||
|
err := applyToNode(n, value, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectByAnnoAndLabel(n *yaml.RNode, t *types.TargetSelector) (bool, error) {
|
||||||
|
if matchesSelect, err := matchesAnnoAndLabelSelector(n, t.Select); !matchesSelect || err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, reject := range t.Reject {
|
||||||
|
if reject.AnnotationSelector == "" && reject.LabelSelector == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m, err := matchesAnnoAndLabelSelector(n, reject); m || err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchesAnnoAndLabelSelector(n *yaml.RNode, selector *types.Selector) (bool, error) {
|
||||||
|
r := resource.Resource{RNode: *n}
|
||||||
|
annoMatch, err := r.MatchesAnnotationSelector(selector.AnnotationSelector)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
labelMatch, err := r.MatchesLabelSelector(selector.LabelSelector)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return annoMatch && labelMatch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rejectId(rejects []*types.Selector, id *resid.ResId) bool {
|
||||||
|
for _, r := range rejects {
|
||||||
|
if !r.ResId.IsEmpty() && id.IsSelectedBy(r.ResId) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelector) error {
|
||||||
|
for _, fp := range target.FieldPaths {
|
||||||
|
fieldPath := utils.SmarterPathSplitter(fp, ".")
|
||||||
|
var t *yaml.RNode
|
||||||
|
var err error
|
||||||
|
if target.Options != nil && target.Options.Create {
|
||||||
|
t, err = node.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
|
||||||
|
} else {
|
||||||
|
t, err = node.Pipe(yaml.Lookup(fieldPath...))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
if err = setTargetValue(target.Options, t, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTargetValue(options *types.FieldOptions, t *yaml.RNode, value *yaml.RNode) error {
|
||||||
|
value = value.Copy()
|
||||||
|
if options != nil && options.Delimiter != "" {
|
||||||
|
if t.YNode().Kind != yaml.ScalarNode {
|
||||||
|
return fmt.Errorf("delimiter option can only be used with scalar nodes")
|
||||||
|
}
|
||||||
|
tv := strings.Split(t.YNode().Value, options.Delimiter)
|
||||||
|
v := yaml.GetValue(value)
|
||||||
|
// TODO: Add a way to remove an element
|
||||||
|
switch {
|
||||||
|
case options.Index < 0: // prefix
|
||||||
|
tv = append([]string{v}, tv...)
|
||||||
|
case options.Index >= len(tv): // suffix
|
||||||
|
tv = append(tv, v)
|
||||||
|
default: // replace an element
|
||||||
|
tv[options.Index] = v
|
||||||
|
}
|
||||||
|
value.YNode().Value = strings.Join(tv, options.Delimiter)
|
||||||
|
}
|
||||||
|
t.SetYNode(value.YNode())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, error) {
|
||||||
|
source, err := selectSourceNode(nodes, r.Source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Source.FieldPath == "" {
|
||||||
|
r.Source.FieldPath = types.DefaultReplacementFieldPath
|
||||||
|
}
|
||||||
|
fieldPath := utils.SmarterPathSplitter(r.Source.FieldPath, ".")
|
||||||
|
|
||||||
|
rn, err := source.Pipe(yaml.Lookup(fieldPath...))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rn.IsNilOrEmpty() {
|
||||||
|
return nil, fmt.Errorf("fieldPath `%s` is missing for replacement source %s", r.Source.FieldPath, r.Source)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRefinedValue(r.Source.Options, rn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
if options == nil || options.Delimiter == "" {
|
||||||
|
return rn, nil
|
||||||
|
}
|
||||||
|
if rn.YNode().Kind != yaml.ScalarNode {
|
||||||
|
return nil, fmt.Errorf("delimiter option can only be used with scalar nodes")
|
||||||
|
}
|
||||||
|
value := strings.Split(yaml.GetValue(rn), options.Delimiter)
|
||||||
|
if options.Index >= len(value) || options.Index < 0 {
|
||||||
|
return nil, fmt.Errorf("options.index %d is out of bounds for value %s", options.Index, yaml.GetValue(rn))
|
||||||
|
}
|
||||||
|
n := rn.Copy()
|
||||||
|
n.YNode().Value = value[options.Index]
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectSourceNode finds the node that matches the selector, returning
|
||||||
|
// an error if multiple or none are found
|
||||||
|
func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) {
|
||||||
|
var matches []*yaml.RNode
|
||||||
|
for _, n := range nodes {
|
||||||
|
ids, err := utils.MakeResIds(n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, id := range ids {
|
||||||
|
if id.IsSelectedBy(selector.ResId) {
|
||||||
|
if len(matches) > 0 {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"multiple matches for selector %s", selector)
|
||||||
|
}
|
||||||
|
matches = append(matches, n)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return nil, fmt.Errorf("nothing selected by %s", selector)
|
||||||
|
}
|
||||||
|
return matches[0], nil
|
||||||
|
}
|
||||||
1839
api/filters/replacement/replacement_test.go
Normal file
1839
api/filters/replacement/replacement_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,10 +33,8 @@ spec:
|
|||||||
Count: 42,
|
Count: 42,
|
||||||
Name: "instance",
|
Name: "instance",
|
||||||
},
|
},
|
||||||
FsSlice: types.FsSlice{
|
FieldSpec: types.FieldSpec{
|
||||||
{
|
Path: "spec/template/replicas",
|
||||||
Path: "spec/template/replicas",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package replicacount
|
|||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/filters/fsslice"
|
"sigs.k8s.io/kustomize/api/filters/fieldspec"
|
||||||
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
@@ -11,10 +12,8 @@ import (
|
|||||||
|
|
||||||
// Filter updates/sets replicas fields using the fieldSpecs
|
// Filter updates/sets replicas fields using the fieldSpecs
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||||
|
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
|
||||||
// FsSlice contains the FieldSpecs to locate the namespace field
|
|
||||||
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ kio.Filter = Filter{}
|
var _ kio.Filter = Filter{}
|
||||||
@@ -23,26 +22,16 @@ func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
|||||||
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
|
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// run processes each node individually.
|
|
||||||
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
meta, err := node.GetMeta()
|
err := node.PipeE(fieldspec.Filter{
|
||||||
if err != nil {
|
FieldSpec: rc.FieldSpec,
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// only update resources where the name matches the Replica name.
|
|
||||||
if meta.Name != rc.Replica.Name {
|
|
||||||
return node, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = node.PipeE(fsslice.Filter{
|
|
||||||
FsSlice: rc.FsSlice,
|
|
||||||
SetValue: rc.set,
|
SetValue: rc.set,
|
||||||
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
|
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
|
||||||
|
CreateTag: yaml.NodeTagInt,
|
||||||
})
|
})
|
||||||
return node, err
|
return node, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc Filter) set(node *yaml.RNode) error {
|
func (rc Filter) set(node *yaml.RNode) error {
|
||||||
return fsslice.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
|
return filtersutil.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,16 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
|
||||||
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
var config = builtinconfig.MakeDefaultConfig()
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
input string
|
input string
|
||||||
expected string
|
expected string
|
||||||
filter Filter
|
filter Filter
|
||||||
fsslice types.FsSlice
|
|
||||||
}{
|
}{
|
||||||
"update field": {
|
"update field": {
|
||||||
input: `
|
input: `
|
||||||
@@ -41,11 +38,7 @@ spec:
|
|||||||
Name: "dep",
|
Name: "dep",
|
||||||
Count: 42,
|
Count: 42,
|
||||||
},
|
},
|
||||||
},
|
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
|
||||||
fsslice: types.FsSlice{
|
|
||||||
{
|
|
||||||
Path: "spec/replicas",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"add field": {
|
"add field": {
|
||||||
@@ -73,9 +66,40 @@ spec:
|
|||||||
Name: "cus",
|
Name: "cus",
|
||||||
Count: 42,
|
Count: 42,
|
||||||
},
|
},
|
||||||
|
FieldSpec: types.FieldSpec{
|
||||||
|
Path: "spec/template/replicas",
|
||||||
|
CreateIfNotPresent: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fsslice: types.FsSlice{
|
},
|
||||||
{
|
|
||||||
|
"add_field_null": {
|
||||||
|
input: `
|
||||||
|
apiVersion: custom/v1
|
||||||
|
kind: Custom
|
||||||
|
metadata:
|
||||||
|
name: cus
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
other: something
|
||||||
|
replicas: null
|
||||||
|
`,
|
||||||
|
expected: `
|
||||||
|
apiVersion: custom/v1
|
||||||
|
kind: Custom
|
||||||
|
metadata:
|
||||||
|
name: cus
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
other: something
|
||||||
|
replicas: 42
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Replica: types.Replica{
|
||||||
|
Name: "cus",
|
||||||
|
Count: 42,
|
||||||
|
},
|
||||||
|
FieldSpec: types.FieldSpec{
|
||||||
Path: "spec/template/replicas",
|
Path: "spec/template/replicas",
|
||||||
CreateIfNotPresent: true,
|
CreateIfNotPresent: true,
|
||||||
},
|
},
|
||||||
@@ -105,9 +129,7 @@ spec:
|
|||||||
Name: "cus",
|
Name: "cus",
|
||||||
Count: 42,
|
Count: 42,
|
||||||
},
|
},
|
||||||
},
|
FieldSpec: types.FieldSpec{
|
||||||
fsslice: types.FsSlice{
|
|
||||||
{
|
|
||||||
Path: "spec/template/replicas",
|
Path: "spec/template/replicas",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -119,7 +141,6 @@ kind: Custom
|
|||||||
metadata:
|
metadata:
|
||||||
name: cus
|
name: cus
|
||||||
spec:
|
spec:
|
||||||
replicas: 5
|
|
||||||
template:
|
template:
|
||||||
replicas: 5
|
replicas: 5
|
||||||
`,
|
`,
|
||||||
@@ -129,7 +150,6 @@ kind: Custom
|
|||||||
metadata:
|
metadata:
|
||||||
name: cus
|
name: cus
|
||||||
spec:
|
spec:
|
||||||
replicas: 42
|
|
||||||
template:
|
template:
|
||||||
replicas: 42
|
replicas: 42
|
||||||
`,
|
`,
|
||||||
@@ -138,21 +158,13 @@ spec:
|
|||||||
Name: "cus",
|
Name: "cus",
|
||||||
Count: 42,
|
Count: 42,
|
||||||
},
|
},
|
||||||
},
|
FieldSpec: types.FieldSpec{Path: "spec/template/replicas"},
|
||||||
fsslice: types.FsSlice{
|
|
||||||
{
|
|
||||||
Path: "spec/template/replicas",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Path: "spec/replicas",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range testCases {
|
for tn, tc := range testCases {
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
tc.filter.FsSlice = append(config.Replicas, tc.fsslice...)
|
|
||||||
if !assert.Equal(t,
|
if !assert.Equal(t,
|
||||||
strings.TrimSpace(tc.expected),
|
strings.TrimSpace(tc.expected),
|
||||||
strings.TrimSpace(
|
strings.TrimSpace(
|
||||||
|
|||||||
134
api/filters/valueadd/valueadd.go
Normal file
134
api/filters/valueadd/valueadd.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package valueadd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An 'Add' operation aspiring to IETF RFC 6902 JSON.
|
||||||
|
//
|
||||||
|
// The filter tries to add a value to a node at a particular field path.
|
||||||
|
//
|
||||||
|
// Kinds of target fields:
|
||||||
|
//
|
||||||
|
// - Non-existent target field.
|
||||||
|
//
|
||||||
|
// The field will be added and the value inserted.
|
||||||
|
//
|
||||||
|
// - Existing field, scalar or map.
|
||||||
|
//
|
||||||
|
// E.g. 'spec/template/spec/containers/[name:nginx]/image'
|
||||||
|
//
|
||||||
|
// This behaves like an IETF RFC 6902 Replace operation would;
|
||||||
|
// the existing value is replaced without complaint, even though
|
||||||
|
// this is an Add operation. In contrast, a Replace operation
|
||||||
|
// must fail (report an error) if the field doesn't exist.
|
||||||
|
//
|
||||||
|
// - Existing field, list (array)
|
||||||
|
// Not supported yet.
|
||||||
|
// TODO: Honor fields with RFC-6902-style array indices
|
||||||
|
// TODO: like 'spec/template/spec/containers/2'
|
||||||
|
// TODO: Modify kyaml/yaml/PathGetter to allow this.
|
||||||
|
// The value will be inserted into the array at the given position,
|
||||||
|
// shifting other contents. To instead replace an array entry, use
|
||||||
|
// an implementation of an IETF RFC 6902 Replace operation.
|
||||||
|
//
|
||||||
|
// For the common case of a filepath in the field value, and a desire
|
||||||
|
// to add the value to the filepath (rather than replace the filepath),
|
||||||
|
// use a non-zero value of FilePathPosition (see below).
|
||||||
|
type Filter struct {
|
||||||
|
// Value is the value to add.
|
||||||
|
//
|
||||||
|
// Empty values are disallowed, i.e. this filter isn't intended
|
||||||
|
// for use in erasing or removing fields. For that, use a filter
|
||||||
|
// more aligned with the IETF RFC 6902 JSON Remove operation.
|
||||||
|
//
|
||||||
|
// At the time of writing, Value's value should be a simple string,
|
||||||
|
// not a JSON document. This particular filter focuses on easing
|
||||||
|
// injection of a single-sourced cloud project and/or cluster name
|
||||||
|
// into various fields, especially namespace and various filepath
|
||||||
|
// specifications.
|
||||||
|
Value string
|
||||||
|
|
||||||
|
// FieldPath is a JSON-style path to the field intended to hold the value.
|
||||||
|
FieldPath string
|
||||||
|
|
||||||
|
// FilePathPosition is a filepath field index.
|
||||||
|
//
|
||||||
|
// Call the value of this field _i_.
|
||||||
|
//
|
||||||
|
// If _i_ is zero, negative or unspecified, this field has no effect.
|
||||||
|
//
|
||||||
|
// If _i_ is > 0, then it's assumed that
|
||||||
|
// - 'Value' is a string that can work as a directory or file name,
|
||||||
|
// - the field value intended for replacement holds a filepath.
|
||||||
|
//
|
||||||
|
// The filepath is split into a string slice, the value is inserted
|
||||||
|
// at position [i-1], shifting the rest of the path to the right.
|
||||||
|
// A value of i==1 puts the new value at the start of the path.
|
||||||
|
// This change never converts an absolute path to a relative path,
|
||||||
|
// meaning adding a new field at position i==1 will preserve a
|
||||||
|
// leading slash. E.g. if Value == 'PEACH'
|
||||||
|
//
|
||||||
|
// OLD : NEW : FilePathPosition
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// {empty} : PEACH : irrelevant
|
||||||
|
// / : /PEACH : irrelevant
|
||||||
|
// pie : PEACH/pie : 1 (or less to prefix)
|
||||||
|
// /pie : /PEACH/pie : 1 (or less to prefix)
|
||||||
|
// raw : raw/PEACH : 2 (or more to postfix)
|
||||||
|
// /raw : /raw/PEACH : 2 (or more to postfix)
|
||||||
|
// a/nice/warm/pie : a/nice/warm/PEACH/pie : 4
|
||||||
|
// /a/nice/warm/pie : /a/nice/warm/PEACH/pie : 4
|
||||||
|
//
|
||||||
|
// For robustness (liberal input, conservative output) FilePathPosition
|
||||||
|
// values that that are too large to index the split filepath result in a
|
||||||
|
// postfix rather than an error. So use 1 to prefix, 9999 to postfix.
|
||||||
|
FilePathPosition int `json:"filePathPosition,omitempty" yaml:"filePathPosition,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ kio.Filter = Filter{}
|
||||||
|
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
_, err := kio.FilterAll(yaml.FilterFunc(
|
||||||
|
func(node *yaml.RNode) (*yaml.RNode, error) {
|
||||||
|
var fields []string
|
||||||
|
// if there is forward slash '/' in the field name, a back slash '\'
|
||||||
|
// will be used to escape it.
|
||||||
|
for _, f := range strings.Split(f.FieldPath, "/") {
|
||||||
|
if len(fields) > 0 && strings.HasSuffix(fields[len(fields)-1], "\\") {
|
||||||
|
concatField := strings.TrimSuffix(fields[len(fields)-1], "\\") + "/" + f
|
||||||
|
fields = append(fields[:len(fields)-1], concatField)
|
||||||
|
} else {
|
||||||
|
fields = append(fields, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: support SequenceNode.
|
||||||
|
// Presumably here one could look for array indices (digits) at
|
||||||
|
// the end of the field path (as described in IETF RFC 6902 JSON),
|
||||||
|
// and if found, take it as a signal that this should be a
|
||||||
|
// SequenceNode instead of a ScalarNode, and insert the value
|
||||||
|
// into the proper slot, shifting every over.
|
||||||
|
n, err := node.Pipe(yaml.LookupCreate(yaml.ScalarNode, fields...))
|
||||||
|
if err != nil {
|
||||||
|
return node, err
|
||||||
|
}
|
||||||
|
// TODO: allow more kinds
|
||||||
|
if err := yaml.ErrorIfInvalid(n, yaml.ScalarNode); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newValue := f.Value
|
||||||
|
if f.FilePathPosition > 0 {
|
||||||
|
newValue = filesys.InsertPathPart(
|
||||||
|
n.YNode().Value, f.FilePathPosition-1, newValue)
|
||||||
|
}
|
||||||
|
return n.Pipe(yaml.FieldSetter{StringValue: newValue})
|
||||||
|
})).Filter(nodes)
|
||||||
|
return nodes, err
|
||||||
|
}
|
||||||
123
api/filters/valueadd/valueadd_test.go
Normal file
123
api/filters/valueadd/valueadd_test.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package valueadd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const someResource = `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: projects/whatever
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestValueAddFilter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
expectedOutput string
|
||||||
|
filter Filter
|
||||||
|
}{
|
||||||
|
"simpleAdd": {
|
||||||
|
input: `
|
||||||
|
kind: SomeKind
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: valueAdded
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef/external",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"replaceExisting": {
|
||||||
|
input: someResource,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: valueAdded
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef/external",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"prefixExisting": {
|
||||||
|
input: someResource,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: valueAdded/projects/whatever
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef/external",
|
||||||
|
FilePathPosition: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"postfixExisting": {
|
||||||
|
input: someResource,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: projects/whatever/valueAdded
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef/external",
|
||||||
|
FilePathPosition: 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"placeInMiddleOfExisting": {
|
||||||
|
input: someResource,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef:
|
||||||
|
external: projects/valueAdded/whatever
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef/external",
|
||||||
|
FilePathPosition: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"backSlash": {
|
||||||
|
input: `
|
||||||
|
kind: SomeKind
|
||||||
|
`,
|
||||||
|
expectedOutput: `
|
||||||
|
kind: SomeKind
|
||||||
|
spec:
|
||||||
|
resourceRef/external: valueAdded
|
||||||
|
`,
|
||||||
|
filter: Filter{
|
||||||
|
Value: "valueAdded",
|
||||||
|
FieldPath: "spec/resourceRef\\/external",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
filter := tc.filter
|
||||||
|
if !assert.Equal(t,
|
||||||
|
strings.TrimSpace(tc.expectedOutput),
|
||||||
|
strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
25
api/go.mod
25
api/go.mod
@@ -1,21 +1,16 @@
|
|||||||
module sigs.k8s.io/kustomize/api
|
module sigs.k8s.io/kustomize/api
|
||||||
|
|
||||||
go 1.13
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
github.com/evanphx/json-patch v4.11.0+incompatible
|
||||||
github.com/go-openapi/spec v0.19.5
|
github.com/go-errors/errors v1.0.1
|
||||||
github.com/golangci/golangci-lint v1.21.0
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/imdario/mergo v0.3.5
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/yujunz/go-getter v1.4.1-lite
|
github.com/stretchr/testify v1.5.1
|
||||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v2 v2.2.7
|
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
|
||||||
k8s.io/api v0.17.0
|
sigs.k8s.io/kustomize/kyaml v0.13.0
|
||||||
k8s.io/apimachinery v0.17.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
k8s.io/client-go v0.17.0
|
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.3
|
|
||||||
sigs.k8s.io/yaml v1.1.0
|
|
||||||
)
|
)
|
||||||
|
|||||||
406
api/go.sum
406
api/go.sum
@@ -1,38 +1,17 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
|
||||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
|
|
||||||
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
|
|
||||||
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
|
||||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
|
||||||
github.com/bombsimon/wsl v1.2.5 h1:9gTOkIwVtoDZywvX802SDHokeX4kW1cKnV8ZTVAPkRs=
|
|
||||||
github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
@@ -40,245 +19,100 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
|
|
||||||
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 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
|
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db h1:GYXWx7Vr3+zv833u+8IoXbNnQY0AdXsxAgI0kX7xcwA=
|
|
||||||
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
|
|
||||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
|
|
||||||
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
|
||||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||||
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
|
||||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
|
||||||
github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw=
|
|
||||||
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
|
|
||||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
|
||||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
|
||||||
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
|
|
||||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
|
||||||
github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
|
||||||
github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ=
|
|
||||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
|
||||||
github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
|
|
||||||
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
|
||||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
|
||||||
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
|
|
||||||
github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
|
|
||||||
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
|
||||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
|
||||||
github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
|
|
||||||
github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg=
|
|
||||||
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
|
|
||||||
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
|
|
||||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
|
||||||
github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA=
|
|
||||||
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
|
||||||
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw=
|
|
||||||
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w=
|
|
||||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
|
|
||||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
|
|
||||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
|
|
||||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
|
|
||||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
|
|
||||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
|
|
||||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
|
|
||||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks=
|
|
||||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
|
||||||
github.com/golangci/golangci-lint v1.21.0 h1:HxAxpR8Z0M8omihvQdsD3PF0qPjlqYqp2vMJzstoKeI=
|
|
||||||
github.com/golangci/golangci-lint v1.21.0/go.mod h1:phxpHK52q7SE+5KpPnti4oZTdFCEsn/tKN+nFvCKXfk=
|
|
||||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
|
|
||||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
|
||||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
|
|
||||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
|
||||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
|
||||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
|
||||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
|
|
||||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
|
||||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSSx3J/s5sVf4Drkc68W2wm4Ixh/mr0us=
|
|
||||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
|
|
||||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg=
|
|
||||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
|
|
||||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
|
|
||||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
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/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
|
|
||||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
|
|
||||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
|
||||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
|
||||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
|
||||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
||||||
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/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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
|
||||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||||
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUCe2BNSOz4tVy2yGyXhvYDvxGgeE=
|
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
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/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||||
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
|
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
|
||||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
|
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
@@ -290,231 +124,107 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
|
|
||||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d h1:BzRvVq1EHuIjxpijCEKpAxzKUUMurOQ4sknehIATRh8=
|
|
||||||
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
|
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
|
||||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=
|
|
||||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
|
||||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=
|
|
||||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs=
|
|
||||||
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e h1:RumXZ56IrCj4CL+g1b9OL/oH0QnsF976bC8xQFYUD5Q=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
|
||||||
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
|
||||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
|
||||||
github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo=
|
|
||||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
|
||||||
github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg=
|
|
||||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
|
||||||
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517 h1:ChMKTho2hWKpks/nD/FL2KqM1wuVt62oJeiE8+eFpGs=
|
|
||||||
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
|
||||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
|
||||||
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
|
|
||||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
|
|
||||||
github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc=
|
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||||
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
|
|
||||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
|
||||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
|
|
||||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
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=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
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.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
|
||||||
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
|
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||||
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
|
||||||
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
|
sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
||||||
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||||
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
|
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||||
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
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 v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
|
||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
|
||||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
|
||||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
|
|
||||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
|
||||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
|
|
||||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
|
||||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
|
|
||||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
|
||||||
sigs.k8s.io/kustomize v1.0.11 h1:Yb+6DDt9+aR2AvQApvUaKS/ugteeG4MPyoFeUHiPOjk=
|
|
||||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.2 h1:l12+QGl+ETUHhP8/bZAi6TknU7H194fXL/9b2gUxZFY=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.3 h1:zbeHVTMCQPtWgjIH/YYJZC45mm7coTdw2TblyJ79BrY=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.1.3/go.mod h1:461i94nj0h0ylJ6w83jLkR4SqqVhn1iY6fjD0JSTQeE=
|
|
||||||
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=
|
|
||||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c=
|
|
||||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SortArrayAndComputeHash sorts a string array and
|
// SortArrayAndComputeHash sorts a string array and
|
||||||
@@ -18,12 +20,12 @@ func SortArrayAndComputeHash(s []string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return Encode(Hash(string(data)))
|
return encode(hex256(string(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from https://github.com/kubernetes/kubernetes
|
// Copied from https://github.com/kubernetes/kubernetes
|
||||||
// /blob/master/pkg/kubectl/util/hash/hash.go
|
// /blob/master/pkg/kubectl/util/hash/hash.go
|
||||||
func Encode(hex string) (string, error) {
|
func encode(hex string) (string, error) {
|
||||||
if len(hex) < 10 {
|
if len(hex) < 10 {
|
||||||
return "", fmt.Errorf(
|
return "", fmt.Errorf(
|
||||||
"input length must be at least 10")
|
"input length must be at least 10")
|
||||||
@@ -46,7 +48,108 @@ func Encode(hex string) (string, error) {
|
|||||||
return string(enc), nil
|
return string(enc), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the hex form of the sha256 of the argument.
|
// hex256 returns the hex form of the sha256 of the argument.
|
||||||
func Hash(data string) string {
|
func hex256(data string) string {
|
||||||
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hasher computes the hash of an RNode.
|
||||||
|
type Hasher struct{}
|
||||||
|
|
||||||
|
// Hash returns a hash of the argument.
|
||||||
|
func (h *Hasher) Hash(node *yaml.RNode) (r string, err error) {
|
||||||
|
var encoded string
|
||||||
|
switch node.GetKind() {
|
||||||
|
case "ConfigMap":
|
||||||
|
encoded, err = encodeConfigMap(node)
|
||||||
|
case "Secret":
|
||||||
|
encoded, err = encodeSecret(node)
|
||||||
|
default:
|
||||||
|
var encodedBytes []byte
|
||||||
|
encodedBytes, err = json.Marshal(node.YNode())
|
||||||
|
encoded = string(encodedBytes)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return encode(hex256(encoded))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeValues(
|
||||||
|
node *yaml.RNode, paths []string) (map[string]interface{}, error) {
|
||||||
|
values := make(map[string]interface{})
|
||||||
|
for _, p := range paths {
|
||||||
|
vn, err := node.Pipe(yaml.Lookup(p))
|
||||||
|
if err != nil {
|
||||||
|
return map[string]interface{}{}, err
|
||||||
|
}
|
||||||
|
if vn == nil {
|
||||||
|
values[p] = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if vn.YNode().Kind != yaml.ScalarNode {
|
||||||
|
vs, err := vn.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return map[string]interface{}{}, err
|
||||||
|
}
|
||||||
|
// data, binaryData and stringData are all maps
|
||||||
|
var v map[string]interface{}
|
||||||
|
json.Unmarshal(vs, &v)
|
||||||
|
values[p] = v
|
||||||
|
} else {
|
||||||
|
values[p] = vn.YNode().Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeConfigMap encodes a ConfigMap.
|
||||||
|
// Data, Kind, and Name are taken into account.
|
||||||
|
// BinaryData is included if it's not empty to avoid useless key in output.
|
||||||
|
func encodeConfigMap(node *yaml.RNode) (string, error) {
|
||||||
|
// get fields
|
||||||
|
paths := []string{"metadata/name", "data", "binaryData"}
|
||||||
|
values, err := getNodeValues(node, paths)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"name": values["metadata/name"],
|
||||||
|
"data": values["data"],
|
||||||
|
}
|
||||||
|
if _, ok := values["binaryData"].(map[string]interface{}); ok {
|
||||||
|
m["binaryData"] = values["binaryData"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
|
data, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeSecret encodes a Secret.
|
||||||
|
// Data, Kind, Name, and Type are taken into account.
|
||||||
|
// StringData is included if it's not empty to avoid useless key in output.
|
||||||
|
func encodeSecret(node *yaml.RNode) (string, error) {
|
||||||
|
// get fields
|
||||||
|
paths := []string{"type", "metadata/name", "data", "stringData"}
|
||||||
|
values, err := getNodeValues(node, paths)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
m := map[string]interface{}{"kind": "Secret", "type": values["type"],
|
||||||
|
"name": values["metadata/name"], "data": values["data"]}
|
||||||
|
if _, ok := values["stringData"].(map[string]interface{}); ok {
|
||||||
|
m["stringData"] = values["stringData"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// json.Marshal sorts the keys in a stable order in the encoding
|
||||||
|
data, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package hasher_test
|
package hasher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "sigs.k8s.io/kustomize/api/hasher"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSortArrayAndComputeHash(t *testing.T) {
|
func TestSortArrayAndComputeHash(t *testing.T) {
|
||||||
@@ -31,11 +32,325 @@ func TestSortArrayAndComputeHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHash(t *testing.T) {
|
func Test_hex256(t *testing.T) {
|
||||||
// hash the empty string to be sure that sha256 is being used
|
// hash the empty string to be sure that sha256 is being used
|
||||||
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
sum := Hash("")
|
sum := hex256("")
|
||||||
if expect != sum {
|
if expect != sum {
|
||||||
t.Errorf("expected hash %q but got %q", expect, sum)
|
t.Errorf("expected hash %q but got %q", expect, sum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigMapHash(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
desc string
|
||||||
|
cmYaml string
|
||||||
|
hash string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
// empty map
|
||||||
|
{"empty data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap`, "6ct58987ht", ""},
|
||||||
|
// one key
|
||||||
|
{"one key", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
one: ""`, "9g67k2htb6", ""},
|
||||||
|
// three keys (tests sorting order)
|
||||||
|
{"three keys", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, "7757f9kkct", ""},
|
||||||
|
// empty binary data map
|
||||||
|
{"empty binary data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap`, "6ct58987ht", ""},
|
||||||
|
// one key with binary data
|
||||||
|
{"one key with binary data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
binaryData:
|
||||||
|
one: ""`, "6mtk2m274t", ""},
|
||||||
|
// three keys with binary data (tests sorting order)
|
||||||
|
{"three keys with binary data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
binaryData:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, "9th7kc28dg", ""},
|
||||||
|
// two keys, one with string and another with binary data
|
||||||
|
{"two keys with one each", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
one: ""
|
||||||
|
binaryData:
|
||||||
|
two: ""`, "698h7c7t9m", ""},
|
||||||
|
}
|
||||||
|
h := &Hasher{}
|
||||||
|
for _, c := range cases {
|
||||||
|
node, err := yaml.Parse(c.cmYaml)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashed, err := h.Hash(node)
|
||||||
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.hash != hashed {
|
||||||
|
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSecretHash(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
desc string
|
||||||
|
secretYaml string
|
||||||
|
hash string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
// empty map
|
||||||
|
{"empty data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type`, "5gmgkf8578", ""},
|
||||||
|
// one key
|
||||||
|
{"one key", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""`, "74bd68bm66", ""},
|
||||||
|
// three keys (tests sorting order)
|
||||||
|
{"three keys", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, "4gf75c7476", ""},
|
||||||
|
// with stringdata
|
||||||
|
{"stringdata", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""
|
||||||
|
stringData:
|
||||||
|
two: 2`, "c4h4264gdb", ""},
|
||||||
|
// empty stringdata
|
||||||
|
{"empty stringdata", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""`, "74bd68bm66", ""},
|
||||||
|
}
|
||||||
|
h := &Hasher{}
|
||||||
|
for _, c := range cases {
|
||||||
|
node, err := yaml.Parse(c.secretYaml)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashed, err := h.Hash(node)
|
||||||
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.hash != hashed {
|
||||||
|
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicHash(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
res string
|
||||||
|
hash string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
"minimal": {`
|
||||||
|
apiVersion: test/v1
|
||||||
|
kind: TestResource
|
||||||
|
metadata:
|
||||||
|
name: my-resource`, "244782mkb7", ""},
|
||||||
|
"with spec": {`
|
||||||
|
apiVersion: test/v1
|
||||||
|
kind: TestResource
|
||||||
|
metadata:
|
||||||
|
name: my-resource
|
||||||
|
spec:
|
||||||
|
foo: 1
|
||||||
|
bar: abc`, "59m2mdccg4", ""},
|
||||||
|
}
|
||||||
|
h := &Hasher{}
|
||||||
|
for n := range cases {
|
||||||
|
c := cases[n]
|
||||||
|
t.Run(n, func(t *testing.T) {
|
||||||
|
node, err := yaml.Parse(c.res)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hashed, err := h.Hash(node)
|
||||||
|
if SkipRest(t, n, err, c.err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.hash != hashed {
|
||||||
|
t.Errorf("case %q, expect hash %q but got %q", n, c.hash, h)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeConfigMap(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
desc string
|
||||||
|
cmYaml string
|
||||||
|
expect string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
// empty map
|
||||||
|
{"empty data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap`, `{"data":"","kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// one key
|
||||||
|
{"one key", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
one: ""`, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// three keys (tests sorting order)
|
||||||
|
{"three keys", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, `{"data":{"one":"","three":3,"two":2},"kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// empty binary map
|
||||||
|
{"empty data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap`, `{"data":"","kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// one key with binary data
|
||||||
|
{"one key", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
binaryData:
|
||||||
|
one: ""`, `{"binaryData":{"one":""},"data":"","kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// three keys with binary data (tests sorting order)
|
||||||
|
{"three keys", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
binaryData:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, `{"binaryData":{"one":"","three":3,"two":2},"data":"","kind":"ConfigMap","name":""}`, ""},
|
||||||
|
// two keys, one string and one binary values
|
||||||
|
{"two keys with one each", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
data:
|
||||||
|
one: ""
|
||||||
|
binaryData:
|
||||||
|
two: ""`, `{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
node, err := yaml.Parse(c.cmYaml)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s, err := encodeConfigMap(node)
|
||||||
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s != c.expect {
|
||||||
|
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.cmYaml)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeSecret(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
desc string
|
||||||
|
secretYaml string
|
||||||
|
expect string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
// empty map
|
||||||
|
{"empty data", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type`, `{"data":"","kind":"Secret","name":"","type":"my-type"}`, ""},
|
||||||
|
// one key
|
||||||
|
{"one key", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""`, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
|
||||||
|
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
|
||||||
|
{"three keys", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
two: 2
|
||||||
|
one: ""
|
||||||
|
three: 3`, `{"data":{"one":"","three":3,"two":2},"kind":"Secret","name":"","type":"my-type"}`, ""},
|
||||||
|
// with stringdata
|
||||||
|
{"stringdata", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""
|
||||||
|
stringData:
|
||||||
|
two: 2`, `{"data":{"one":""},"kind":"Secret","name":"","stringData":{"two":2},"type":"my-type"}`, ""},
|
||||||
|
// empty stringdata
|
||||||
|
{"empty stringdata", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
type: my-type
|
||||||
|
data:
|
||||||
|
one: ""`, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
node, err := yaml.Parse(c.secretYaml)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s, err := encodeSecret(node)
|
||||||
|
if SkipRest(t, c.desc, err, c.err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s != c.expect {
|
||||||
|
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.secretYaml)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipRest returns true if there was a non-nil error or if we expected an
|
||||||
|
// error that didn't happen, and logs the appropriate error on the test object.
|
||||||
|
// The return value indicates whether we should skip the rest of the test case
|
||||||
|
// due to the error result.
|
||||||
|
func SkipRest(t *testing.T, desc string, err error, contains string) bool {
|
||||||
|
if err != nil {
|
||||||
|
if len(contains) == 0 {
|
||||||
|
t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
|
||||||
|
} else if !strings.Contains(err.Error(), contains) {
|
||||||
|
t.Errorf("case %q, expect error to contain %q but got %q", desc, contains, err.Error())
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else if len(contains) > 0 {
|
||||||
|
t.Errorf("case %q, expect error to contain %q but got nil error", desc, contains)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
package ifc
|
package ifc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/api/resid"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validator provides functions to validate annotations and labels
|
// Validator provides functions to validate annotations and labels
|
||||||
@@ -38,57 +38,10 @@ type Loader interface {
|
|||||||
Cleanup() error
|
Cleanup() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kunstructured allows manipulation of k8s objects
|
// KustHasher returns a hash of the argument
|
||||||
// that do not have Golang structs.
|
|
||||||
type Kunstructured interface {
|
|
||||||
Map() map[string]interface{}
|
|
||||||
SetMap(map[string]interface{})
|
|
||||||
Copy() Kunstructured
|
|
||||||
GetFieldValue(string) (interface{}, error)
|
|
||||||
GetString(string) (string, error)
|
|
||||||
GetStringSlice(string) ([]string, error)
|
|
||||||
GetBool(path string) (bool, error)
|
|
||||||
GetFloat64(path string) (float64, error)
|
|
||||||
GetInt64(path string) (int64, error)
|
|
||||||
GetSlice(path string) ([]interface{}, error)
|
|
||||||
GetStringMap(path string) (map[string]string, error)
|
|
||||||
GetMap(path string) (map[string]interface{}, error)
|
|
||||||
MarshalJSON() ([]byte, error)
|
|
||||||
UnmarshalJSON([]byte) error
|
|
||||||
GetGvk() resid.Gvk
|
|
||||||
SetGvk(resid.Gvk)
|
|
||||||
GetKind() string
|
|
||||||
GetName() string
|
|
||||||
SetName(string)
|
|
||||||
SetNamespace(string)
|
|
||||||
GetLabels() map[string]string
|
|
||||||
SetLabels(map[string]string)
|
|
||||||
GetAnnotations() map[string]string
|
|
||||||
SetAnnotations(map[string]string)
|
|
||||||
MatchesLabelSelector(selector string) (bool, error)
|
|
||||||
MatchesAnnotationSelector(selector string) (bool, error)
|
|
||||||
Patch(Kunstructured) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// KunstructuredFactory makes instances of Kunstructured.
|
|
||||||
type KunstructuredFactory interface {
|
|
||||||
SliceFromBytes([]byte) ([]Kunstructured, error)
|
|
||||||
FromMap(m map[string]interface{}) Kunstructured
|
|
||||||
Hasher() KunstructuredHasher
|
|
||||||
MakeConfigMap(
|
|
||||||
kvLdr KvLoader,
|
|
||||||
options *types.GeneratorOptions,
|
|
||||||
args *types.ConfigMapArgs) (Kunstructured, error)
|
|
||||||
MakeSecret(
|
|
||||||
kvLdr KvLoader,
|
|
||||||
options *types.GeneratorOptions,
|
|
||||||
args *types.SecretArgs) (Kunstructured, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KunstructuredHasher returns a hash of the argument
|
|
||||||
// or an error.
|
// or an error.
|
||||||
type KunstructuredHasher interface {
|
type KustHasher interface {
|
||||||
Hash(Kunstructured) (string, error)
|
Hash(*yaml.RNode) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// See core.v1.SecretTypeOpaque
|
// See core.v1.SecretTypeOpaque
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user