update modules kustomize add helm
Signed-off-by: LiHui <andrewli@yunify.com>
This commit is contained in:
14
go.mod
14
go.mod
@@ -84,7 +84,7 @@ require (
|
||||
gopkg.in/square/go-jose.v2 v2.4.0
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
gotest.tools v2.2.0+incompatible
|
||||
helm.sh/helm/v3 v3.3.0
|
||||
@@ -111,7 +111,7 @@ require (
|
||||
sigs.k8s.io/controller-runtime v0.6.4
|
||||
sigs.k8s.io/controller-tools v0.4.1
|
||||
sigs.k8s.io/kubefed v0.6.1
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible
|
||||
sigs.k8s.io/kustomize/api v0.8.6
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
@@ -301,6 +301,7 @@ replace (
|
||||
github.com/gliderlabs/ssh => github.com/gliderlabs/ssh v0.1.1
|
||||
github.com/glycerine/go-unsnap-stream => github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
|
||||
github.com/glycerine/goconvey => github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31
|
||||
github.com/go-errors/errors => github.com/go-errors/errors v1.0.1
|
||||
github.com/go-kit/kit => github.com/go-kit/kit v0.10.0
|
||||
github.com/go-ldap/ldap => github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.0
|
||||
@@ -329,6 +330,7 @@ replace (
|
||||
github.com/gobuffalo/genny => github.com/gobuffalo/genny v0.1.1
|
||||
github.com/gobuffalo/gitgen => github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211
|
||||
github.com/gobuffalo/gogen => github.com/gobuffalo/gogen v0.1.1
|
||||
github.com/gobuffalo/here => github.com/gobuffalo/here v0.6.0
|
||||
github.com/gobuffalo/logger => github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2
|
||||
github.com/gobuffalo/mapi => github.com/gobuffalo/mapi v1.0.2
|
||||
github.com/gobuffalo/packd => github.com/gobuffalo/packd v0.1.0
|
||||
@@ -371,6 +373,7 @@ replace (
|
||||
github.com/google/martian => github.com/google/martian v2.1.0+incompatible
|
||||
github.com/google/pprof => github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a
|
||||
github.com/google/renameio => github.com/google/renameio v0.1.0
|
||||
github.com/google/shlex => github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid => github.com/google/uuid v1.1.1
|
||||
github.com/googleapis/gax-go => github.com/googleapis/gax-go v2.0.2+incompatible
|
||||
github.com/googleapis/gax-go/v2 => github.com/googleapis/gax-go/v2 v2.0.5
|
||||
@@ -472,6 +475,7 @@ replace (
|
||||
github.com/magiconair/properties => github.com/magiconair/properties v1.8.0
|
||||
github.com/mailru/easyjson => github.com/mailru/easyjson v0.7.1
|
||||
github.com/markbates/oncer => github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2
|
||||
github.com/markbates/pkger => github.com/markbates/pkger v0.17.1
|
||||
github.com/markbates/safe => github.com/markbates/safe v1.0.1
|
||||
github.com/mattn/go-colorable => github.com/mattn/go-colorable v0.1.6
|
||||
github.com/mattn/go-ieproxy => github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe
|
||||
@@ -502,6 +506,7 @@ replace (
|
||||
github.com/mna/pigeon => github.com/mna/pigeon v0.0.0-20180808201053-bb0192cfc2ae
|
||||
github.com/modern-go/concurrent => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1
|
||||
github.com/monochromegane/go-gitignore => github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
|
||||
github.com/montanaflynn/stats => github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe
|
||||
github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
|
||||
github.com/mozillazg/go-cos => github.com/mozillazg/go-cos v0.13.0
|
||||
@@ -651,6 +656,7 @@ replace (
|
||||
go.etcd.io/etcd => go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738
|
||||
go.mongodb.org/mongo-driver => go.mongodb.org/mongo-driver v1.3.2
|
||||
go.opencensus.io => go.opencensus.io v0.22.3
|
||||
go.starlark.net => go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5
|
||||
go.uber.org/atomic => go.uber.org/atomic v1.6.0
|
||||
go.uber.org/automaxprocs => go.uber.org/automaxprocs v1.2.0
|
||||
go.uber.org/goleak => go.uber.org/goleak v1.1.0
|
||||
@@ -704,7 +710,7 @@ replace (
|
||||
gopkg.in/tchap/go-patricia.v2 => gopkg.in/tchap/go-patricia.v2 v2.2.6
|
||||
gopkg.in/tomb.v1 => gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
|
||||
gopkg.in/warnings.v0 => gopkg.in/warnings.v0 v0.1.2
|
||||
gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
gotest.tools => gotest.tools v2.2.0+incompatible
|
||||
helm.sh/helm/v3 => helm.sh/helm/v3 v3.3.0
|
||||
@@ -743,6 +749,8 @@ replace (
|
||||
sigs.k8s.io/kind => sigs.k8s.io/kind v0.8.1
|
||||
sigs.k8s.io/kubefed => sigs.k8s.io/kubefed v0.6.1
|
||||
sigs.k8s.io/kustomize => sigs.k8s.io/kustomize v2.0.3+incompatible
|
||||
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.8.6
|
||||
sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.10.17
|
||||
sigs.k8s.io/structured-merge-diff/v3 => sigs.k8s.io/structured-merge-diff/v3 v3.0.0
|
||||
sigs.k8s.io/yaml => sigs.k8s.io/yaml v1.2.0
|
||||
sourcegraph.com/sourcegraph/appdash => sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0
|
||||
|
||||
21
go.sum
21
go.sum
@@ -247,6 +247,8 @@ github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
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-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk=
|
||||
@@ -295,6 +297,7 @@ github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7
|
||||
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
|
||||
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
|
||||
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
@@ -351,6 +354,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
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/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
@@ -481,6 +486,7 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
||||
github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -488,6 +494,7 @@ github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6I
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||
@@ -520,6 +527,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
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/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
@@ -544,6 +553,7 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
@@ -708,6 +718,7 @@ github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6 h1:YdYsPAZ2pC6Tow/nPZOPQ96O3hm/ToAkGsPLzedXERk=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b h1:vVRagRXf67ESqAb72hG2C/ZwI8NtJF2u2V76EsuOHGY=
|
||||
@@ -728,6 +739,8 @@ go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mI
|
||||
go.mongodb.org/mongo-driver v1.3.2 h1:IYppNjEV/C+/3VPbhHVxQ4t04eVW0cLp0/pNdW++6Ug=
|
||||
go.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
|
||||
@@ -812,8 +825,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
@@ -879,6 +892,10 @@ sigs.k8s.io/kubefed v0.6.1 h1:5NqfXCYPG1UC7H2KCs8tX77XN1ohHv+VegkZ69UWvF0=
|
||||
sigs.k8s.io/kubefed v0.6.1/go.mod h1:dP40OsC2z1m2uzkk8YiTMdaO/Y8/2zvAAWfGuYnJTKU=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||
sigs.k8s.io/kustomize/api v0.8.6 h1:RZf3FAoNQ4LMGaTJsyWV4V9PP9n1fts2qLM116T+oto=
|
||||
sigs.k8s.io/kustomize/api v0.8.6/go.mod h1:GTpbRQ3zkL079aWRS5x2+lVbVSgNR9w4SHnfQyhC7ME=
|
||||
sigs.k8s.io/kustomize/kyaml v0.10.17 h1:4zrV0ym5AYa0e512q7K3Wp1u7mzoWW0xR3UHJcGWGIg=
|
||||
sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
|
||||
5
vendor/github.com/go-errors/errors/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/go-errors/errors/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.8.x"
|
||||
- "1.10.x"
|
||||
7
vendor/github.com/go-errors/errors/LICENSE.MIT
generated
vendored
Normal file
7
vendor/github.com/go-errors/errors/LICENSE.MIT
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2015 Conrad Irwin <conrad@bugsnag.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
66
vendor/github.com/go-errors/errors/README.md
generated
vendored
Normal file
66
vendor/github.com/go-errors/errors/README.md
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
go-errors/errors
|
||||
================
|
||||
|
||||
[](https://travis-ci.org/go-errors/errors)
|
||||
|
||||
Package errors adds stacktrace support to errors in go.
|
||||
|
||||
This is particularly useful when you want to understand the state of execution
|
||||
when an error was returned unexpectedly.
|
||||
|
||||
It provides the type \*Error which implements the standard golang error
|
||||
interface, so you can use this library interchangably with code that is
|
||||
expecting a normal error return.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Full documentation is available on
|
||||
[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple
|
||||
example:
|
||||
|
||||
```go
|
||||
package crashy
|
||||
|
||||
import "github.com/go-errors/errors"
|
||||
|
||||
var Crashed = errors.Errorf("oh dear")
|
||||
|
||||
func Crash() error {
|
||||
return errors.New(Crashed)
|
||||
}
|
||||
```
|
||||
|
||||
This can be called as follows:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crashy"
|
||||
"fmt"
|
||||
"github.com/go-errors/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := crashy.Crash()
|
||||
if err != nil {
|
||||
if errors.Is(err, crashy.Crashed) {
|
||||
fmt.Println(err.(*errors.Error).ErrorStack())
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Meta-fu
|
||||
-------
|
||||
|
||||
This package was original written to allow reporting to
|
||||
[Bugsnag](https://bugsnag.com/) from
|
||||
[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar
|
||||
packages by Facebook and Dropbox, it was moved to one canonical location so
|
||||
everyone can benefit.
|
||||
|
||||
This package is licensed under the MIT license, see LICENSE.MIT for details.
|
||||
217
vendor/github.com/go-errors/errors/error.go
generated
vendored
Normal file
217
vendor/github.com/go-errors/errors/error.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
// Package errors provides errors that have stack-traces.
|
||||
//
|
||||
// This is particularly useful when you want to understand the
|
||||
// state of execution when an error was returned unexpectedly.
|
||||
//
|
||||
// It provides the type *Error which implements the standard
|
||||
// golang error interface, so you can use this library interchangably
|
||||
// with code that is expecting a normal error return.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// package crashy
|
||||
//
|
||||
// import "github.com/go-errors/errors"
|
||||
//
|
||||
// var Crashed = errors.Errorf("oh dear")
|
||||
//
|
||||
// func Crash() error {
|
||||
// return errors.New(Crashed)
|
||||
// }
|
||||
//
|
||||
// This can be called as follows:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "crashy"
|
||||
// "fmt"
|
||||
// "github.com/go-errors/errors"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// err := crashy.Crash()
|
||||
// if err != nil {
|
||||
// if errors.Is(err, crashy.Crashed) {
|
||||
// fmt.Println(err.(*errors.Error).ErrorStack())
|
||||
// } else {
|
||||
// panic(err)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This package was original written to allow reporting to Bugsnag,
|
||||
// but after I found similar packages by Facebook and Dropbox, it
|
||||
// was moved to one canonical location so everyone can benefit.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// The maximum number of stackframes on any error.
|
||||
var MaxStackDepth = 50
|
||||
|
||||
// Error is an error with an attached stacktrace. It can be used
|
||||
// wherever the builtin error interface is expected.
|
||||
type Error struct {
|
||||
Err error
|
||||
stack []uintptr
|
||||
frames []StackFrame
|
||||
prefix string
|
||||
}
|
||||
|
||||
// New makes an Error from the given value. If that value is already an
|
||||
// error then it will be used directly, if not, it will be passed to
|
||||
// fmt.Errorf("%v"). The stacktrace will point to the line of code that
|
||||
// called New.
|
||||
func New(e interface{}) *Error {
|
||||
var err error
|
||||
|
||||
switch e := e.(type) {
|
||||
case error:
|
||||
err = e
|
||||
default:
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
|
||||
stack := make([]uintptr, MaxStackDepth)
|
||||
length := runtime.Callers(2, stack[:])
|
||||
return &Error{
|
||||
Err: err,
|
||||
stack: stack[:length],
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap makes an Error from the given value. If that value is already an
|
||||
// error then it will be used directly, if not, it will be passed to
|
||||
// fmt.Errorf("%v"). The skip parameter indicates how far up the stack
|
||||
// to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
|
||||
func Wrap(e interface{}, skip int) *Error {
|
||||
var err error
|
||||
|
||||
switch e := e.(type) {
|
||||
case *Error:
|
||||
return e
|
||||
case error:
|
||||
err = e
|
||||
default:
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
|
||||
stack := make([]uintptr, MaxStackDepth)
|
||||
length := runtime.Callers(2+skip, stack[:])
|
||||
return &Error{
|
||||
Err: err,
|
||||
stack: stack[:length],
|
||||
}
|
||||
}
|
||||
|
||||
// WrapPrefix makes an Error from the given value. If that value is already an
|
||||
// error then it will be used directly, if not, it will be passed to
|
||||
// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the
|
||||
// error message when calling Error(). The skip parameter indicates how far
|
||||
// up the stack to start the stacktrace. 0 is from the current call,
|
||||
// 1 from its caller, etc.
|
||||
func WrapPrefix(e interface{}, prefix string, skip int) *Error {
|
||||
|
||||
err := Wrap(e, 1+skip)
|
||||
|
||||
if err.prefix != "" {
|
||||
prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
|
||||
}
|
||||
|
||||
return &Error{
|
||||
Err: err.Err,
|
||||
stack: err.stack,
|
||||
prefix: prefix,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Is detects whether the error is equal to a given error. Errors
|
||||
// are considered equal by this function if they are the same object,
|
||||
// or if they both contain the same error inside an errors.Error.
|
||||
func Is(e error, original error) bool {
|
||||
|
||||
if e == original {
|
||||
return true
|
||||
}
|
||||
|
||||
if e, ok := e.(*Error); ok {
|
||||
return Is(e.Err, original)
|
||||
}
|
||||
|
||||
if original, ok := original.(*Error); ok {
|
||||
return Is(e, original.Err)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Errorf creates a new error with the given message. You can use it
|
||||
// as a drop-in replacement for fmt.Errorf() to provide descriptive
|
||||
// errors in return values.
|
||||
func Errorf(format string, a ...interface{}) *Error {
|
||||
return Wrap(fmt.Errorf(format, a...), 1)
|
||||
}
|
||||
|
||||
// Error returns the underlying error's message.
|
||||
func (err *Error) Error() string {
|
||||
|
||||
msg := err.Err.Error()
|
||||
if err.prefix != "" {
|
||||
msg = fmt.Sprintf("%s: %s", err.prefix, msg)
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
// Stack returns the callstack formatted the same way that go does
|
||||
// in runtime/debug.Stack()
|
||||
func (err *Error) Stack() []byte {
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
for _, frame := range err.StackFrames() {
|
||||
buf.WriteString(frame.String())
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// Callers satisfies the bugsnag ErrorWithCallerS() interface
|
||||
// so that the stack can be read out.
|
||||
func (err *Error) Callers() []uintptr {
|
||||
return err.stack
|
||||
}
|
||||
|
||||
// ErrorStack returns a string that contains both the
|
||||
// error message and the callstack.
|
||||
func (err *Error) ErrorStack() string {
|
||||
return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
|
||||
}
|
||||
|
||||
// StackFrames returns an array of frames containing information about the
|
||||
// stack.
|
||||
func (err *Error) StackFrames() []StackFrame {
|
||||
if err.frames == nil {
|
||||
err.frames = make([]StackFrame, len(err.stack))
|
||||
|
||||
for i, pc := range err.stack {
|
||||
err.frames[i] = NewStackFrame(pc)
|
||||
}
|
||||
}
|
||||
|
||||
return err.frames
|
||||
}
|
||||
|
||||
// TypeName returns the type this error. e.g. *errors.stringError.
|
||||
func (err *Error) TypeName() string {
|
||||
if _, ok := err.Err.(uncaughtPanic); ok {
|
||||
return "panic"
|
||||
}
|
||||
return reflect.TypeOf(err.Err).String()
|
||||
}
|
||||
127
vendor/github.com/go-errors/errors/parse_panic.go
generated
vendored
Normal file
127
vendor/github.com/go-errors/errors/parse_panic.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type uncaughtPanic struct{ message string }
|
||||
|
||||
func (p uncaughtPanic) Error() string {
|
||||
return p.message
|
||||
}
|
||||
|
||||
// ParsePanic allows you to get an error object from the output of a go program
|
||||
// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap.
|
||||
func ParsePanic(text string) (*Error, error) {
|
||||
lines := strings.Split(text, "\n")
|
||||
|
||||
state := "start"
|
||||
|
||||
var message string
|
||||
var stack []StackFrame
|
||||
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
|
||||
if state == "start" {
|
||||
if strings.HasPrefix(line, "panic: ") {
|
||||
message = strings.TrimPrefix(line, "panic: ")
|
||||
state = "seek"
|
||||
} else {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line)
|
||||
}
|
||||
|
||||
} else if state == "seek" {
|
||||
if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") {
|
||||
state = "parsing"
|
||||
}
|
||||
|
||||
} else if state == "parsing" {
|
||||
if line == "" {
|
||||
state = "done"
|
||||
break
|
||||
}
|
||||
createdBy := false
|
||||
if strings.HasPrefix(line, "created by ") {
|
||||
line = strings.TrimPrefix(line, "created by ")
|
||||
createdBy = true
|
||||
}
|
||||
|
||||
i++
|
||||
|
||||
if i >= len(lines) {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line)
|
||||
}
|
||||
|
||||
frame, err := parsePanicFrame(line, lines[i], createdBy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stack = append(stack, *frame)
|
||||
if createdBy {
|
||||
state = "done"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state == "done" || state == "parsing" {
|
||||
return &Error{Err: uncaughtPanic{message}, frames: stack}, nil
|
||||
}
|
||||
return nil, Errorf("could not parse panic: %v", text)
|
||||
}
|
||||
|
||||
// The lines we're passing look like this:
|
||||
//
|
||||
// main.(*foo).destruct(0xc208067e98)
|
||||
// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151
|
||||
func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) {
|
||||
idx := strings.LastIndex(name, "(")
|
||||
if idx == -1 && !createdBy {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name)
|
||||
}
|
||||
if idx != -1 {
|
||||
name = name[:idx]
|
||||
}
|
||||
pkg := ""
|
||||
|
||||
if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
|
||||
pkg += name[:lastslash] + "/"
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
if period := strings.Index(name, "."); period >= 0 {
|
||||
pkg += name[:period]
|
||||
name = name[period+1:]
|
||||
}
|
||||
|
||||
name = strings.Replace(name, "·", ".", -1)
|
||||
|
||||
if !strings.HasPrefix(line, "\t") {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line)
|
||||
}
|
||||
|
||||
idx = strings.LastIndex(line, ":")
|
||||
if idx == -1 {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line)
|
||||
}
|
||||
file := line[1:idx]
|
||||
|
||||
number := line[idx+1:]
|
||||
if idx = strings.Index(number, " +"); idx > -1 {
|
||||
number = number[:idx]
|
||||
}
|
||||
|
||||
lno, err := strconv.ParseInt(number, 10, 32)
|
||||
if err != nil {
|
||||
return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line)
|
||||
}
|
||||
|
||||
return &StackFrame{
|
||||
File: file,
|
||||
LineNumber: int(lno),
|
||||
Package: pkg,
|
||||
Name: name,
|
||||
}, nil
|
||||
}
|
||||
102
vendor/github.com/go-errors/errors/stackframe.go
generated
vendored
Normal file
102
vendor/github.com/go-errors/errors/stackframe.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A StackFrame contains all necessary information about to generate a line
|
||||
// in a callstack.
|
||||
type StackFrame struct {
|
||||
// The path to the file containing this ProgramCounter
|
||||
File string
|
||||
// The LineNumber in that file
|
||||
LineNumber int
|
||||
// The Name of the function that contains this ProgramCounter
|
||||
Name string
|
||||
// The Package that contains this function
|
||||
Package string
|
||||
// The underlying ProgramCounter
|
||||
ProgramCounter uintptr
|
||||
}
|
||||
|
||||
// NewStackFrame popoulates a stack frame object from the program counter.
|
||||
func NewStackFrame(pc uintptr) (frame StackFrame) {
|
||||
|
||||
frame = StackFrame{ProgramCounter: pc}
|
||||
if frame.Func() == nil {
|
||||
return
|
||||
}
|
||||
frame.Package, frame.Name = packageAndName(frame.Func())
|
||||
|
||||
// pc -1 because the program counters we use are usually return addresses,
|
||||
// and we want to show the line that corresponds to the function call
|
||||
frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Func returns the function that contained this frame.
|
||||
func (frame *StackFrame) Func() *runtime.Func {
|
||||
if frame.ProgramCounter == 0 {
|
||||
return nil
|
||||
}
|
||||
return runtime.FuncForPC(frame.ProgramCounter)
|
||||
}
|
||||
|
||||
// String returns the stackframe formatted in the same way as go does
|
||||
// in runtime/debug.Stack()
|
||||
func (frame *StackFrame) String() string {
|
||||
str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter)
|
||||
|
||||
source, err := frame.SourceLine()
|
||||
if err != nil {
|
||||
return str
|
||||
}
|
||||
|
||||
return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source)
|
||||
}
|
||||
|
||||
// SourceLine gets the line of code (from File and Line) of the original source if possible.
|
||||
func (frame *StackFrame) SourceLine() (string, error) {
|
||||
data, err := ioutil.ReadFile(frame.File)
|
||||
|
||||
if err != nil {
|
||||
return "", New(err)
|
||||
}
|
||||
|
||||
lines := bytes.Split(data, []byte{'\n'})
|
||||
if frame.LineNumber <= 0 || frame.LineNumber >= len(lines) {
|
||||
return "???", nil
|
||||
}
|
||||
// -1 because line-numbers are 1 based, but our array is 0 based
|
||||
return string(bytes.Trim(lines[frame.LineNumber-1], " \t")), nil
|
||||
}
|
||||
|
||||
func packageAndName(fn *runtime.Func) (string, string) {
|
||||
name := fn.Name()
|
||||
pkg := ""
|
||||
|
||||
// The name includes the path name to the package, which is unnecessary
|
||||
// since the file name is already included. Plus, it has center dots.
|
||||
// That is, we see
|
||||
// runtime/debug.*T·ptrmethod
|
||||
// and want
|
||||
// *T.ptrmethod
|
||||
// Since the package path might contains dots (e.g. code.google.com/...),
|
||||
// we first remove the path prefix if there is one.
|
||||
if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
|
||||
pkg += name[:lastslash] + "/"
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
if period := strings.Index(name, "."); period >= 0 {
|
||||
pkg += name[:period]
|
||||
name = name[period+1:]
|
||||
}
|
||||
|
||||
name = strings.Replace(name, "·", ".", -1)
|
||||
return pkg, name
|
||||
}
|
||||
1
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
1
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
@@ -11,6 +11,7 @@ go:
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
- "1.14.x"
|
||||
- "tip"
|
||||
|
||||
go_import_path: gopkg.in/yaml.v2
|
||||
|
||||
6
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
6
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
@@ -79,6 +79,8 @@ func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
|
||||
parser.encoding = encoding
|
||||
}
|
||||
|
||||
var disableLineWrapping = false
|
||||
|
||||
// Create a new emitter object.
|
||||
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
||||
*emitter = yaml_emitter_t{
|
||||
@@ -86,7 +88,9 @@ func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
||||
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
||||
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
||||
events: make([]yaml_event_t, 0, initial_queue_size),
|
||||
best_width: -1,
|
||||
}
|
||||
if disableLineWrapping {
|
||||
emitter.best_width = -1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
vendor/gopkg.in/yaml.v2/go.mod
generated
vendored
8
vendor/gopkg.in/yaml.v2/go.mod
generated
vendored
@@ -1,5 +1,5 @@
|
||||
module "gopkg.in/yaml.v2"
|
||||
module gopkg.in/yaml.v2
|
||||
|
||||
require (
|
||||
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
|
||||
)
|
||||
go 1.15
|
||||
|
||||
require gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
|
||||
|
||||
14
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
14
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
@@ -175,7 +175,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be included if that method returns true.
|
||||
// case the field will be excluded if IsZero returns true.
|
||||
//
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
@@ -464,3 +464,15 @@ func isZero(v reflect.Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FutureLineWrap globally disables line wrapping when encoding long strings.
|
||||
// This is a temporary and thus deprecated method introduced to faciliate
|
||||
// migration towards v3, which offers more control of line lengths on
|
||||
// individual encodings, and has a default matching the behavior introduced
|
||||
// by this function.
|
||||
//
|
||||
// The default formatting of v2 was erroneously changed in v2.3.0 and reverted
|
||||
// in v2.4.0, at which point this function was introduced to help migration.
|
||||
func FutureLineWrap() {
|
||||
disableLineWrapping = true
|
||||
}
|
||||
|
||||
178
vendor/helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util/deploymentutil.go
vendored
Normal file
178
vendor/helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util/deploymentutil.go
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
intstrutil "k8s.io/apimachinery/pkg/util/intstr"
|
||||
appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
)
|
||||
|
||||
// deploymentutil contains a copy of a few functions from Kubernetes controller code to avoid a dependency on k8s.io/kubernetes.
|
||||
// This code is copied from https://github.com/kubernetes/kubernetes/blob/e856613dd5bb00bcfaca6974431151b5c06cbed5/pkg/controller/deployment/util/deployment_util.go
|
||||
// No changes to the code were made other than removing some unused functions
|
||||
|
||||
// RsListFunc returns the ReplicaSet from the ReplicaSet namespace and the List metav1.ListOptions.
|
||||
type RsListFunc func(string, metav1.ListOptions) ([]*apps.ReplicaSet, error)
|
||||
|
||||
// ListReplicaSets returns a slice of RSes the given deployment targets.
|
||||
// Note that this does NOT attempt to reconcile ControllerRef (adopt/orphan),
|
||||
// because only the controller itself should do that.
|
||||
// However, it does filter out anything whose ControllerRef doesn't match.
|
||||
func ListReplicaSets(deployment *apps.Deployment, getRSList RsListFunc) ([]*apps.ReplicaSet, error) {
|
||||
// TODO: Right now we list replica sets by their labels. We should list them by selector, i.e. the replica set's selector
|
||||
// should be a superset of the deployment's selector, see https://github.com/kubernetes/kubernetes/issues/19830.
|
||||
namespace := deployment.Namespace
|
||||
selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := metav1.ListOptions{LabelSelector: selector.String()}
|
||||
all, err := getRSList(namespace, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Only include those whose ControllerRef matches the Deployment.
|
||||
owned := make([]*apps.ReplicaSet, 0, len(all))
|
||||
for _, rs := range all {
|
||||
if metav1.IsControlledBy(rs, deployment) {
|
||||
owned = append(owned, rs)
|
||||
}
|
||||
}
|
||||
return owned, nil
|
||||
}
|
||||
|
||||
// ReplicaSetsByCreationTimestamp sorts a list of ReplicaSet by creation timestamp, using their names as a tie breaker.
|
||||
type ReplicaSetsByCreationTimestamp []*apps.ReplicaSet
|
||||
|
||||
func (o ReplicaSetsByCreationTimestamp) Len() int { return len(o) }
|
||||
func (o ReplicaSetsByCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
|
||||
func (o ReplicaSetsByCreationTimestamp) Less(i, j int) bool {
|
||||
if o[i].CreationTimestamp.Equal(&o[j].CreationTimestamp) {
|
||||
return o[i].Name < o[j].Name
|
||||
}
|
||||
return o[i].CreationTimestamp.Before(&o[j].CreationTimestamp)
|
||||
}
|
||||
|
||||
// FindNewReplicaSet returns the new RS this given deployment targets (the one with the same pod template).
|
||||
func FindNewReplicaSet(deployment *apps.Deployment, rsList []*apps.ReplicaSet) *apps.ReplicaSet {
|
||||
sort.Sort(ReplicaSetsByCreationTimestamp(rsList))
|
||||
for i := range rsList {
|
||||
if EqualIgnoreHash(&rsList[i].Spec.Template, &deployment.Spec.Template) {
|
||||
// In rare cases, such as after cluster upgrades, Deployment may end up with
|
||||
// having more than one new ReplicaSets that have the same template as its template,
|
||||
// see https://github.com/kubernetes/kubernetes/issues/40415
|
||||
// We deterministically choose the oldest new ReplicaSet.
|
||||
return rsList[i]
|
||||
}
|
||||
}
|
||||
// new ReplicaSet does not exist.
|
||||
return nil
|
||||
}
|
||||
|
||||
// EqualIgnoreHash returns true if two given podTemplateSpec are equal, ignoring the diff in value of Labels[pod-template-hash]
|
||||
// We ignore pod-template-hash because:
|
||||
// 1. The hash result would be different upon podTemplateSpec API changes
|
||||
// (e.g. the addition of a new field will cause the hash code to change)
|
||||
// 2. The deployment template won't have hash labels
|
||||
func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) bool {
|
||||
t1Copy := template1.DeepCopy()
|
||||
t2Copy := template2.DeepCopy()
|
||||
// Remove hash labels from template.Labels before comparing
|
||||
delete(t1Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
|
||||
delete(t2Copy.Labels, apps.DefaultDeploymentUniqueLabelKey)
|
||||
return apiequality.Semantic.DeepEqual(t1Copy, t2Copy)
|
||||
}
|
||||
|
||||
// GetNewReplicaSet returns a replica set that matches the intent of the given deployment; get ReplicaSetList from client interface.
|
||||
// Returns nil if the new replica set doesn't exist yet.
|
||||
func GetNewReplicaSet(deployment *apps.Deployment, c appsclient.AppsV1Interface) (*apps.ReplicaSet, error) {
|
||||
rsList, err := ListReplicaSets(deployment, RsListFromClient(c))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FindNewReplicaSet(deployment, rsList), nil
|
||||
}
|
||||
|
||||
// RsListFromClient returns an rsListFunc that wraps the given client.
|
||||
func RsListFromClient(c appsclient.AppsV1Interface) RsListFunc {
|
||||
return func(namespace string, options metav1.ListOptions) ([]*apps.ReplicaSet, error) {
|
||||
rsList, err := c.ReplicaSets(namespace).List(context.Background(), options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ret []*apps.ReplicaSet
|
||||
for i := range rsList.Items {
|
||||
ret = append(ret, &rsList.Items[i])
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
// IsRollingUpdate returns true if the strategy type is a rolling update.
|
||||
func IsRollingUpdate(deployment *apps.Deployment) bool {
|
||||
return deployment.Spec.Strategy.Type == apps.RollingUpdateDeploymentStrategyType
|
||||
}
|
||||
|
||||
// MaxUnavailable returns the maximum unavailable pods a rolling deployment can take.
|
||||
func MaxUnavailable(deployment apps.Deployment) int32 {
|
||||
if !IsRollingUpdate(&deployment) || *(deployment.Spec.Replicas) == 0 {
|
||||
return int32(0)
|
||||
}
|
||||
// Error caught by validation
|
||||
_, maxUnavailable, _ := ResolveFenceposts(deployment.Spec.Strategy.RollingUpdate.MaxSurge, deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, *(deployment.Spec.Replicas))
|
||||
if maxUnavailable > *deployment.Spec.Replicas {
|
||||
return *deployment.Spec.Replicas
|
||||
}
|
||||
return maxUnavailable
|
||||
}
|
||||
|
||||
// ResolveFenceposts resolves both maxSurge and maxUnavailable. This needs to happen in one
|
||||
// step. For example:
|
||||
//
|
||||
// 2 desired, max unavailable 1%, surge 0% - should scale old(-1), then new(+1), then old(-1), then new(+1)
|
||||
// 1 desired, max unavailable 1%, surge 0% - should scale old(-1), then new(+1)
|
||||
// 2 desired, max unavailable 25%, surge 1% - should scale new(+1), then old(-1), then new(+1), then old(-1)
|
||||
// 1 desired, max unavailable 25%, surge 1% - should scale new(+1), then old(-1)
|
||||
// 2 desired, max unavailable 0%, surge 1% - should scale new(+1), then old(-1), then new(+1), then old(-1)
|
||||
// 1 desired, max unavailable 0%, surge 1% - should scale new(+1), then old(-1)
|
||||
func ResolveFenceposts(maxSurge, maxUnavailable *intstrutil.IntOrString, desired int32) (int32, int32, error) {
|
||||
surge, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxSurge, intstrutil.FromInt(0)), int(desired), true)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
unavailable, err := intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(maxUnavailable, intstrutil.FromInt(0)), int(desired), false)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if surge == 0 && unavailable == 0 {
|
||||
// Validation should never allow the user to explicitly use zero values for both maxSurge
|
||||
// maxUnavailable. Due to rounding down maxUnavailable though, it may resolve to zero.
|
||||
// If both fenceposts resolve to zero, then we should set maxUnavailable to 1 on the
|
||||
// theory that surge might not work due to quota.
|
||||
unavailable = 1
|
||||
}
|
||||
|
||||
return int32(surge), int32(unavailable), nil
|
||||
}
|
||||
598
vendor/helm.sh/helm/v3/pkg/kube/client.go
vendored
Normal file
598
vendor/helm.sh/helm/v3/pkg/kube/client.go
vendored
Normal file
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/pkg/errors"
|
||||
batch "k8s.io/api/batch/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
cachetools "k8s.io/client-go/tools/cache"
|
||||
watchtools "k8s.io/client-go/tools/watch"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
|
||||
// ErrNoObjectsVisited indicates that during a visit operation, no matching objects were found.
|
||||
var ErrNoObjectsVisited = errors.New("no objects visited")
|
||||
|
||||
var metadataAccessor = meta.NewAccessor()
|
||||
|
||||
// Client represents a client capable of communicating with the Kubernetes API.
|
||||
type Client struct {
|
||||
Factory Factory
|
||||
Log func(string, ...interface{})
|
||||
// Namespace allows to bypass the kubeconfig file for the choice of the namespace
|
||||
Namespace string
|
||||
}
|
||||
|
||||
var addToScheme sync.Once
|
||||
|
||||
// New creates a new Client.
|
||||
func New(getter genericclioptions.RESTClientGetter) *Client {
|
||||
if getter == nil {
|
||||
getter = genericclioptions.NewConfigFlags(true)
|
||||
}
|
||||
// Add CRDs to the scheme. They are missing by default.
|
||||
addToScheme.Do(func() {
|
||||
if err := apiextv1.AddToScheme(scheme.Scheme); err != nil {
|
||||
// This should never happen.
|
||||
panic(err)
|
||||
}
|
||||
if err := apiextv1beta1.AddToScheme(scheme.Scheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
return &Client{
|
||||
Factory: cmdutil.NewFactory(getter),
|
||||
Log: nopLogger,
|
||||
}
|
||||
}
|
||||
|
||||
var nopLogger = func(_ string, _ ...interface{}) {}
|
||||
|
||||
// IsReachable tests connectivity to the cluster
|
||||
func (c *Client) IsReachable() error {
|
||||
client, err := c.Factory.KubernetesClientSet()
|
||||
if err == genericclioptions.ErrEmptyConfig {
|
||||
// re-replace kubernetes ErrEmptyConfig error with a friendy error
|
||||
// moar workarounds for Kubernetes API breaking.
|
||||
return errors.New("Kubernetes cluster unreachable")
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Kubernetes cluster unreachable")
|
||||
}
|
||||
if _, err := client.ServerVersion(); err != nil {
|
||||
return errors.Wrap(err, "Kubernetes cluster unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create creates Kubernetes resources specified in the resource list.
|
||||
func (c *Client) Create(resources ResourceList) (*Result, error) {
|
||||
c.Log("creating %d resource(s)", len(resources))
|
||||
if err := perform(resources, createResource); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Result{Created: resources}, nil
|
||||
}
|
||||
|
||||
// Wait up to the given timeout for the specified resources to be ready
|
||||
func (c *Client) Wait(resources ResourceList, timeout time.Duration) error {
|
||||
cs, err := c.Factory.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := waiter{
|
||||
c: cs,
|
||||
log: c.Log,
|
||||
timeout: timeout,
|
||||
}
|
||||
return w.waitForResources(resources)
|
||||
}
|
||||
|
||||
func (c *Client) namespace() string {
|
||||
if c.Namespace != "" {
|
||||
return c.Namespace
|
||||
}
|
||||
if ns, _, err := c.Factory.ToRawKubeConfigLoader().Namespace(); err == nil {
|
||||
return ns
|
||||
}
|
||||
return v1.NamespaceDefault
|
||||
}
|
||||
|
||||
// newBuilder returns a new resource builder for structured api objects.
|
||||
func (c *Client) newBuilder() *resource.Builder {
|
||||
return c.Factory.NewBuilder().
|
||||
ContinueOnError().
|
||||
NamespaceParam(c.namespace()).
|
||||
DefaultNamespace().
|
||||
Flatten()
|
||||
}
|
||||
|
||||
// Build validates for Kubernetes objects and returns unstructured infos.
|
||||
func (c *Client) Build(reader io.Reader, validate bool) (ResourceList, error) {
|
||||
schema, err := c.Factory.Validator(validate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := c.newBuilder().
|
||||
Unstructured().
|
||||
Schema(schema).
|
||||
Stream(reader, "").
|
||||
Do().Infos()
|
||||
return result, scrubValidationError(err)
|
||||
}
|
||||
|
||||
// Update takes the current list of objects and target list of objects and
|
||||
// creates resources that don't already exists, updates resources that have been
|
||||
// modified in the target configuration, and deletes resources from the current
|
||||
// configuration that are not present in the target configuration. If an error
|
||||
// occurs, a Result will still be returned with the error, containing all
|
||||
// resource updates, creations, and deletions that were attempted. These can be
|
||||
// used for cleanup or other logging purposes.
|
||||
func (c *Client) Update(original, target ResourceList, force bool) (*Result, error) {
|
||||
updateErrors := []string{}
|
||||
res := &Result{}
|
||||
|
||||
c.Log("checking %d resources for changes", len(target))
|
||||
err := target.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
if _, err := helper.Get(info.Namespace, info.Name, info.Export); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return errors.Wrap(err, "could not get information about the resource")
|
||||
}
|
||||
|
||||
// Append the created resource to the results, even if something fails
|
||||
res.Created = append(res.Created, info)
|
||||
|
||||
// Since the resource does not exist, create it.
|
||||
if err := createResource(info); err != nil {
|
||||
return errors.Wrap(err, "failed to create resource")
|
||||
}
|
||||
|
||||
kind := info.Mapping.GroupVersionKind.Kind
|
||||
c.Log("Created a new %s called %q in %s\n", kind, info.Name, info.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
originalInfo := original.Get(info)
|
||||
if originalInfo == nil {
|
||||
kind := info.Mapping.GroupVersionKind.Kind
|
||||
return errors.Errorf("no %s with the name %q found", kind, info.Name)
|
||||
}
|
||||
|
||||
if err := updateResource(c, info, originalInfo.Object, force); err != nil {
|
||||
c.Log("error updating the resource %q:\n\t %v", info.Name, err)
|
||||
updateErrors = append(updateErrors, err.Error())
|
||||
}
|
||||
// Because we check for errors later, append the info regardless
|
||||
res.Updated = append(res.Updated, info)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return res, err
|
||||
case len(updateErrors) != 0:
|
||||
return res, errors.Errorf(strings.Join(updateErrors, " && "))
|
||||
}
|
||||
|
||||
for _, info := range original.Difference(target) {
|
||||
c.Log("Deleting %q in %s...", info.Name, info.Namespace)
|
||||
|
||||
if err := info.Get(); err != nil {
|
||||
c.Log("Unable to get obj %q, err: %s", info.Name, err)
|
||||
continue
|
||||
}
|
||||
annotations, err := metadataAccessor.Annotations(info.Object)
|
||||
if err != nil {
|
||||
c.Log("Unable to get annotations on %q, err: %s", info.Name, err)
|
||||
}
|
||||
if annotations != nil && annotations[ResourcePolicyAnno] == KeepPolicy {
|
||||
c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy)
|
||||
continue
|
||||
}
|
||||
if err := deleteResource(info); err != nil {
|
||||
c.Log("Failed to delete %q, err: %s", info.ObjectName(), err)
|
||||
continue
|
||||
}
|
||||
res.Deleted = append(res.Deleted, info)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Delete deletes Kubernetes resources specified in the resources list. It will
|
||||
// attempt to delete all resources even if one or more fail and collect any
|
||||
// errors. All successfully deleted items will be returned in the `Deleted`
|
||||
// ResourceList that is part of the result.
|
||||
func (c *Client) Delete(resources ResourceList) (*Result, []error) {
|
||||
var errs []error
|
||||
res := &Result{}
|
||||
mtx := sync.Mutex{}
|
||||
err := perform(resources, func(info *resource.Info) error {
|
||||
c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind)
|
||||
if err := c.skipIfNotFound(deleteResource(info)); err != nil {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
// Collect the error and continue on
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
res.Deleted = append(res.Deleted, info)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
// Rewrite the message from "no objects visited" if that is what we got
|
||||
// back
|
||||
if err == ErrNoObjectsVisited {
|
||||
err = errors.New("object not found, skipping delete")
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Client) skipIfNotFound(err error) error {
|
||||
if apierrors.IsNotFound(err) {
|
||||
c.Log("%v", err)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) watchTimeout(t time.Duration) func(*resource.Info) error {
|
||||
return func(info *resource.Info) error {
|
||||
return c.watchUntilReady(t, info)
|
||||
}
|
||||
}
|
||||
|
||||
// WatchUntilReady watches the resources given and waits until it is ready.
|
||||
//
|
||||
// This function is mainly for hook implementations. It watches for a resource to
|
||||
// hit a particular milestone. The milestone depends on the Kind.
|
||||
//
|
||||
// For most kinds, it checks to see if the resource is marked as Added or Modified
|
||||
// by the Kubernetes event stream. For some kinds, it does more:
|
||||
//
|
||||
// - Jobs: A job is marked "Ready" when it has successfully completed. This is
|
||||
// ascertained by watching the Status fields in a job's output.
|
||||
// - Pods: A pod is marked "Ready" when it has successfully completed. This is
|
||||
// ascertained by watching the status.phase field in a pod's output.
|
||||
//
|
||||
// Handling for other kinds will be added as necessary.
|
||||
func (c *Client) WatchUntilReady(resources ResourceList, timeout time.Duration) error {
|
||||
// For jobs, there's also the option to do poll c.Jobs(namespace).Get():
|
||||
// https://github.com/adamreese/kubernetes/blob/master/test/e2e/job.go#L291-L300
|
||||
return perform(resources, c.watchTimeout(timeout))
|
||||
}
|
||||
|
||||
func perform(infos ResourceList, fn func(*resource.Info) error) error {
|
||||
if len(infos) == 0 {
|
||||
return ErrNoObjectsVisited
|
||||
}
|
||||
|
||||
errs := make(chan error)
|
||||
go batchPerform(infos, fn, errs)
|
||||
|
||||
for range infos {
|
||||
err := <-errs
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func batchPerform(infos ResourceList, fn func(*resource.Info) error, errs chan<- error) {
|
||||
var kind string
|
||||
var wg sync.WaitGroup
|
||||
for _, info := range infos {
|
||||
currentKind := info.Object.GetObjectKind().GroupVersionKind().Kind
|
||||
if kind != currentKind {
|
||||
wg.Wait()
|
||||
kind = currentKind
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(i *resource.Info) {
|
||||
errs <- fn(i)
|
||||
wg.Done()
|
||||
}(info)
|
||||
}
|
||||
}
|
||||
|
||||
func createResource(info *resource.Info) error {
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return info.Refresh(obj, true)
|
||||
}
|
||||
|
||||
func deleteResource(info *resource.Info) error {
|
||||
policy := metav1.DeletePropagationBackground
|
||||
opts := &metav1.DeleteOptions{PropagationPolicy: &policy}
|
||||
_, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.PatchType, error) {
|
||||
oldData, err := json.Marshal(current)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing current configuration")
|
||||
}
|
||||
newData, err := json.Marshal(target.Object)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing target configuration")
|
||||
}
|
||||
|
||||
// Fetch the current object for the three way merge
|
||||
helper := resource.NewHelper(target.Client, target.Mapping)
|
||||
currentObj, err := helper.Get(target.Namespace, target.Name, target.Export)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name)
|
||||
}
|
||||
|
||||
// Even if currentObj is nil (because it was not found), it will marshal just fine
|
||||
currentData, err := json.Marshal(currentObj)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing live configuration")
|
||||
}
|
||||
|
||||
// Get a versioned object
|
||||
versionedObject := AsVersioned(target)
|
||||
|
||||
// Unstructured objects, such as CRDs, may not have an not registered error
|
||||
// returned from ConvertToVersion. Anything that's unstructured should
|
||||
// use the jsonpatch.CreateMergePatch. Strategic Merge Patch is not supported
|
||||
// on objects like CRDs.
|
||||
_, isUnstructured := versionedObject.(runtime.Unstructured)
|
||||
|
||||
// On newer K8s versions, CRDs aren't unstructured but has this dedicated type
|
||||
_, isCRD := versionedObject.(*apiextv1beta1.CustomResourceDefinition)
|
||||
|
||||
if isUnstructured || isCRD {
|
||||
// fall back to generic JSON merge patch
|
||||
patch, err := jsonpatch.CreateMergePatch(oldData, newData)
|
||||
return patch, types.MergePatchType, err
|
||||
}
|
||||
|
||||
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, errors.Wrap(err, "unable to create patch metadata from object")
|
||||
}
|
||||
|
||||
patch, err := strategicpatch.CreateThreeWayMergePatch(oldData, newData, currentData, patchMeta, true)
|
||||
return patch, types.StrategicMergePatchType, err
|
||||
}
|
||||
|
||||
func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error {
|
||||
var (
|
||||
obj runtime.Object
|
||||
helper = resource.NewHelper(target.Client, target.Mapping)
|
||||
kind = target.Mapping.GroupVersionKind.Kind
|
||||
)
|
||||
|
||||
// if --force is applied, attempt to replace the existing resource with the new object.
|
||||
if force {
|
||||
var err error
|
||||
obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to replace object")
|
||||
}
|
||||
c.Log("Replaced %q with kind %s for kind %s", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind)
|
||||
} else {
|
||||
patch, patchType, err := createPatch(target, currentObj)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create patch")
|
||||
}
|
||||
|
||||
if patch == nil || string(patch) == "{}" {
|
||||
c.Log("Looks like there are no changes for %s %q", target.Mapping.GroupVersionKind.Kind, target.Name)
|
||||
// This needs to happen to make sure that Helm has the latest info from the API
|
||||
// Otherwise there will be no labels and other functions that use labels will panic
|
||||
if err := target.Get(); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh resource information")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// send patch to server
|
||||
obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot patch %q with kind %s", target.Name, kind)
|
||||
}
|
||||
}
|
||||
|
||||
target.Refresh(obj, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) error {
|
||||
kind := info.Mapping.GroupVersionKind.Kind
|
||||
switch kind {
|
||||
case "Job", "Pod":
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Log("Watching for changes to %s %s with timeout of %v", kind, info.Name, timeout)
|
||||
|
||||
// Use a selector on the name of the resource. This should be unique for the
|
||||
// given version and kind
|
||||
selector, err := fields.ParseSelector(fmt.Sprintf("metadata.name=%s", info.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lw := cachetools.NewListWatchFromClient(info.Client, info.Mapping.Resource.Resource, info.Namespace, selector)
|
||||
|
||||
// What we watch for depends on the Kind.
|
||||
// - For a Job, we watch for completion.
|
||||
// - For all else, we watch until Ready.
|
||||
// In the future, we might want to add some special logic for types
|
||||
// like Ingress, Volume, etc.
|
||||
|
||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
_, err = watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) {
|
||||
// Make sure the incoming object is versioned as we use unstructured
|
||||
// objects when we build manifests
|
||||
obj := convertWithMapper(e.Object, info.Mapping)
|
||||
switch e.Type {
|
||||
case watch.Added, watch.Modified:
|
||||
// For things like a secret or a config map, this is the best indicator
|
||||
// we get. We care mostly about jobs, where what we want to see is
|
||||
// the status go into a good state. For other types, like ReplicaSet
|
||||
// we don't really do anything to support these as hooks.
|
||||
c.Log("Add/Modify event for %s: %v", info.Name, e.Type)
|
||||
switch kind {
|
||||
case "Job":
|
||||
return c.waitForJob(obj, info.Name)
|
||||
case "Pod":
|
||||
return c.waitForPodSuccess(obj, info.Name)
|
||||
}
|
||||
return true, nil
|
||||
case watch.Deleted:
|
||||
c.Log("Deleted event for %s", info.Name)
|
||||
return true, nil
|
||||
case watch.Error:
|
||||
// Handle error and return with an error.
|
||||
c.Log("Error event for %s", info.Name)
|
||||
return true, errors.Errorf("failed to deploy %s", info.Name)
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// waitForJob is a helper that waits for a job to complete.
|
||||
//
|
||||
// This operates on an event returned from a watcher.
|
||||
func (c *Client) waitForJob(obj runtime.Object, name string) (bool, error) {
|
||||
o, ok := obj.(*batch.Job)
|
||||
if !ok {
|
||||
return true, errors.Errorf("expected %s to be a *batch.Job, got %T", name, obj)
|
||||
}
|
||||
|
||||
for _, c := range o.Status.Conditions {
|
||||
if c.Type == batch.JobComplete && c.Status == "True" {
|
||||
return true, nil
|
||||
} else if c.Type == batch.JobFailed && c.Status == "True" {
|
||||
return true, errors.Errorf("job failed: %s", c.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
c.Log("%s: Jobs active: %d, jobs failed: %d, jobs succeeded: %d", name, o.Status.Active, o.Status.Failed, o.Status.Succeeded)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// waitForPodSuccess is a helper that waits for a pod to complete.
|
||||
//
|
||||
// This operates on an event returned from a watcher.
|
||||
func (c *Client) waitForPodSuccess(obj runtime.Object, name string) (bool, error) {
|
||||
o, ok := obj.(*v1.Pod)
|
||||
if !ok {
|
||||
return true, errors.Errorf("expected %s to be a *v1.Pod, got %T", name, obj)
|
||||
}
|
||||
|
||||
switch o.Status.Phase {
|
||||
case v1.PodSucceeded:
|
||||
fmt.Printf("Pod %s succeeded\n", o.Name)
|
||||
return true, nil
|
||||
case v1.PodFailed:
|
||||
return true, errors.Errorf("pod %s failed", o.Name)
|
||||
case v1.PodPending:
|
||||
fmt.Printf("Pod %s pending\n", o.Name)
|
||||
case v1.PodRunning:
|
||||
fmt.Printf("Pod %s running\n", o.Name)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// scrubValidationError removes kubectl info from the message.
|
||||
func scrubValidationError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
const stopValidateMessage = "if you choose to ignore these errors, turn validation off with --validate=false"
|
||||
|
||||
if strings.Contains(err.Error(), stopValidateMessage) {
|
||||
return errors.New(strings.ReplaceAll(err.Error(), "; "+stopValidateMessage, ""))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
|
||||
// and returns said phase (PodSucceeded or PodFailed qualify).
|
||||
func (c *Client) WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error) {
|
||||
client, err := c.Factory.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return v1.PodUnknown, err
|
||||
}
|
||||
to := int64(timeout)
|
||||
watcher, err := client.CoreV1().Pods(c.namespace()).Watch(context.Background(), metav1.ListOptions{
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
||||
TimeoutSeconds: &to,
|
||||
})
|
||||
|
||||
for event := range watcher.ResultChan() {
|
||||
p, ok := event.Object.(*v1.Pod)
|
||||
if !ok {
|
||||
return v1.PodUnknown, fmt.Errorf("%s not a pod", name)
|
||||
}
|
||||
switch p.Status.Phase {
|
||||
case v1.PodFailed:
|
||||
return v1.PodFailed, nil
|
||||
case v1.PodSucceeded:
|
||||
return v1.PodSucceeded, nil
|
||||
}
|
||||
}
|
||||
|
||||
return v1.PodUnknown, err
|
||||
}
|
||||
30
vendor/helm.sh/helm/v3/pkg/kube/config.go
vendored
Normal file
30
vendor/helm.sh/helm/v3/pkg/kube/config.go
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import "k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
|
||||
// GetConfig returns a Kubernetes client config.
|
||||
//
|
||||
// Deprecated
|
||||
func GetConfig(kubeconfig, context, namespace string) *genericclioptions.ConfigFlags {
|
||||
cf := genericclioptions.NewConfigFlags(true)
|
||||
cf.Namespace = &namespace
|
||||
cf.Context = &context
|
||||
cf.KubeConfig = &kubeconfig
|
||||
return cf
|
||||
}
|
||||
69
vendor/helm.sh/helm/v3/pkg/kube/converter.go
vendored
Normal file
69
vendor/helm.sh/helm/v3/pkg/kube/converter.go
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var k8sNativeScheme *runtime.Scheme
|
||||
var k8sNativeSchemeOnce sync.Once
|
||||
|
||||
// AsVersioned converts the given info into a runtime.Object with the correct
|
||||
// group and version set
|
||||
func AsVersioned(info *resource.Info) runtime.Object {
|
||||
return convertWithMapper(info.Object, info.Mapping)
|
||||
}
|
||||
|
||||
// convertWithMapper converts the given object with the optional provided
|
||||
// RESTMapping. If no mapping is provided, the default schema versioner is used
|
||||
func convertWithMapper(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object {
|
||||
s := kubernetesNativeScheme()
|
||||
var gv = runtime.GroupVersioner(schema.GroupVersions(s.PrioritizedVersionsAllGroups()))
|
||||
if mapping != nil {
|
||||
gv = mapping.GroupVersionKind.GroupVersion()
|
||||
}
|
||||
if obj, err := runtime.ObjectConvertor(s).ConvertToVersion(obj, gv); err == nil {
|
||||
return obj
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// kubernetesNativeScheme returns a clean *runtime.Scheme with _only_ Kubernetes
|
||||
// native resources added to it. This is required to break free of custom resources
|
||||
// that may have been added to scheme.Scheme due to Helm being used as a package in
|
||||
// combination with e.g. a versioned kube client. If we would not do this, the client
|
||||
// may attempt to perform e.g. a 3-way-merge strategy patch for custom resources.
|
||||
func kubernetesNativeScheme() *runtime.Scheme {
|
||||
k8sNativeSchemeOnce.Do(func() {
|
||||
k8sNativeScheme = runtime.NewScheme()
|
||||
scheme.AddToScheme(k8sNativeScheme)
|
||||
// API extensions are not in the above scheme set,
|
||||
// and must thus be added separately.
|
||||
apiextensionsv1beta1.AddToScheme(k8sNativeScheme)
|
||||
apiextensionsv1.AddToScheme(k8sNativeScheme)
|
||||
})
|
||||
return k8sNativeScheme
|
||||
}
|
||||
38
vendor/helm.sh/helm/v3/pkg/kube/factory.go
vendored
Normal file
38
vendor/helm.sh/helm/v3/pkg/kube/factory.go
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import (
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubectl/pkg/validation"
|
||||
)
|
||||
|
||||
// Factory provides abstractions that allow the Kubectl command to be extended across multiple types
|
||||
// of resources and different API sets.
|
||||
type Factory interface {
|
||||
// ToRawKubeConfigLoader return kubeconfig loader as-is
|
||||
ToRawKubeConfigLoader() clientcmd.ClientConfig
|
||||
// KubernetesClientSet gives you back an external clientset
|
||||
KubernetesClientSet() (*kubernetes.Clientset, error)
|
||||
// NewBuilder returns an object that assists in loading objects from both disk and the server
|
||||
// and which implements the common patterns for CLI interactions with generic resources.
|
||||
NewBuilder() *resource.Builder
|
||||
// Returns a schema that can validate objects stored on disk.
|
||||
Validator(validate bool) (validation.Schema, error)
|
||||
}
|
||||
66
vendor/helm.sh/helm/v3/pkg/kube/interface.go
vendored
Normal file
66
vendor/helm.sh/helm/v3/pkg/kube/interface.go
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// Interface represents a client capable of communicating with the Kubernetes API.
|
||||
//
|
||||
// A KubernetesClient must be concurrency safe.
|
||||
type Interface interface {
|
||||
// Create creates one or more resources.
|
||||
Create(resources ResourceList) (*Result, error)
|
||||
|
||||
Wait(resources ResourceList, timeout time.Duration) error
|
||||
|
||||
// Delete destroys one or more resources.
|
||||
Delete(resources ResourceList) (*Result, []error)
|
||||
|
||||
// Watch the resource in reader until it is "ready". This method
|
||||
//
|
||||
// For Jobs, "ready" means the Job ran to completion (exited without error).
|
||||
// For Pods, "ready" means the Pod phase is marked "succeeded".
|
||||
// For all other kinds, it means the kind was created or modified without
|
||||
// error.
|
||||
WatchUntilReady(resources ResourceList, timeout time.Duration) error
|
||||
|
||||
// Update updates one or more resources or creates the resource
|
||||
// if it doesn't exist.
|
||||
Update(original, target ResourceList, force bool) (*Result, error)
|
||||
|
||||
// Build creates a resource list from a Reader
|
||||
//
|
||||
// reader must contain a YAML stream (one or more YAML documents separated
|
||||
// by "\n---\n")
|
||||
//
|
||||
// Validates against OpenAPI schema if validate is true.
|
||||
Build(reader io.Reader, validate bool) (ResourceList, error)
|
||||
|
||||
// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase
|
||||
// and returns said phase (PodSucceeded or PodFailed qualify).
|
||||
WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error)
|
||||
|
||||
// isReachable checks whether the client is able to connect to the cluster
|
||||
IsReachable() error
|
||||
}
|
||||
|
||||
var _ Interface = (*Client)(nil)
|
||||
85
vendor/helm.sh/helm/v3/pkg/kube/resource.go
vendored
Normal file
85
vendor/helm.sh/helm/v3/pkg/kube/resource.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import "k8s.io/cli-runtime/pkg/resource"
|
||||
|
||||
// ResourceList provides convenience methods for comparing collections of Infos.
|
||||
type ResourceList []*resource.Info
|
||||
|
||||
// Append adds an Info to the Result.
|
||||
func (r *ResourceList) Append(val *resource.Info) {
|
||||
*r = append(*r, val)
|
||||
}
|
||||
|
||||
// Visit implements resource.Visitor.
|
||||
func (r ResourceList) Visit(fn resource.VisitorFunc) error {
|
||||
for _, i := range r {
|
||||
if err := fn(i, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter returns a new Result with Infos that satisfy the predicate fn.
|
||||
func (r ResourceList) Filter(fn func(*resource.Info) bool) ResourceList {
|
||||
var result ResourceList
|
||||
for _, i := range r {
|
||||
if fn(i) {
|
||||
result.Append(i)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Get returns the Info from the result that matches the name and kind.
|
||||
func (r ResourceList) Get(info *resource.Info) *resource.Info {
|
||||
for _, i := range r {
|
||||
if isMatchingInfo(i, info) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains checks to see if an object exists.
|
||||
func (r ResourceList) Contains(info *resource.Info) bool {
|
||||
for _, i := range r {
|
||||
if isMatchingInfo(i, info) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference will return a new Result with objects not contained in rs.
|
||||
func (r ResourceList) Difference(rs ResourceList) ResourceList {
|
||||
return r.Filter(func(info *resource.Info) bool {
|
||||
return !rs.Contains(info)
|
||||
})
|
||||
}
|
||||
|
||||
// Intersect will return a new Result with objects contained in both Results.
|
||||
func (r ResourceList) Intersect(rs ResourceList) ResourceList {
|
||||
return r.Filter(rs.Contains)
|
||||
}
|
||||
|
||||
// isMatchingInfo returns true if infos match on Name and GroupVersionKind.
|
||||
func isMatchingInfo(a, b *resource.Info) bool {
|
||||
return a.Name == b.Name && a.Namespace == b.Namespace && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind
|
||||
}
|
||||
26
vendor/helm.sh/helm/v3/pkg/kube/resource_policy.go
vendored
Normal file
26
vendor/helm.sh/helm/v3/pkg/kube/resource_policy.go
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
// ResourcePolicyAnno is the annotation name for a resource policy
|
||||
const ResourcePolicyAnno = "helm.sh/resource-policy"
|
||||
|
||||
// KeepPolicy is the resource policy type for keep
|
||||
//
|
||||
// This resource policy type allows resources to skip being deleted
|
||||
// during an uninstallRelease action.
|
||||
const KeepPolicy = "keep"
|
||||
28
vendor/helm.sh/helm/v3/pkg/kube/result.go
vendored
Normal file
28
vendor/helm.sh/helm/v3/pkg/kube/result.go
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
// Result contains the information of created, updated, and deleted resources
|
||||
// for various kube API calls along with helper methods for using those
|
||||
// resources
|
||||
type Result struct {
|
||||
Created ResourceList
|
||||
Updated ResourceList
|
||||
Deleted ResourceList
|
||||
}
|
||||
|
||||
// If needed, we can add methods to the Result type for things like diffing
|
||||
393
vendor/helm.sh/helm/v3/pkg/kube/wait.go
vendored
Normal file
393
vendor/helm.sh/helm/v3/pkg/kube/wait.go
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube // import "helm.sh/helm/v3/pkg/kube"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
appsv1beta1 "k8s.io/api/apps/v1beta1"
|
||||
appsv1beta2 "k8s.io/api/apps/v1beta2"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
deploymentutil "helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util"
|
||||
)
|
||||
|
||||
type waiter struct {
|
||||
c kubernetes.Interface
|
||||
timeout time.Duration
|
||||
log func(string, ...interface{})
|
||||
}
|
||||
|
||||
// waitForResources polls to get the current status of all pods, PVCs, and Services
|
||||
// until all are ready or a timeout is reached
|
||||
func (w *waiter) waitForResources(created ResourceList) error {
|
||||
w.log("beginning wait for %d resources with timeout of %v", len(created), w.timeout)
|
||||
|
||||
return wait.Poll(2*time.Second, w.timeout, func() (bool, error) {
|
||||
for _, v := range created {
|
||||
var (
|
||||
// This defaults to true, otherwise we get to a point where
|
||||
// things will always return false unless one of the objects
|
||||
// that manages pods has been hit
|
||||
ok = true
|
||||
err error
|
||||
)
|
||||
switch value := AsVersioned(v).(type) {
|
||||
case *corev1.Pod:
|
||||
pod, err := w.c.CoreV1().Pods(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil || !w.isPodReady(pod) {
|
||||
return false, err
|
||||
}
|
||||
case *appsv1.Deployment, *appsv1beta1.Deployment, *appsv1beta2.Deployment, *extensionsv1beta1.Deployment:
|
||||
currentDeployment, err := w.c.AppsV1().Deployments(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// If paused deployment will never be ready
|
||||
if currentDeployment.Spec.Paused {
|
||||
continue
|
||||
}
|
||||
// Find RS associated with deployment
|
||||
newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, w.c.AppsV1())
|
||||
if err != nil || newReplicaSet == nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.deploymentReady(newReplicaSet, currentDeployment) {
|
||||
return false, nil
|
||||
}
|
||||
case *corev1.PersistentVolumeClaim:
|
||||
claim, err := w.c.CoreV1().PersistentVolumeClaims(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.volumeReady(claim) {
|
||||
return false, nil
|
||||
}
|
||||
case *corev1.Service:
|
||||
svc, err := w.c.CoreV1().Services(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.serviceReady(svc) {
|
||||
return false, nil
|
||||
}
|
||||
case *extensionsv1beta1.DaemonSet, *appsv1.DaemonSet, *appsv1beta2.DaemonSet:
|
||||
ds, err := w.c.AppsV1().DaemonSets(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.daemonSetReady(ds) {
|
||||
return false, nil
|
||||
}
|
||||
case *apiextv1beta1.CustomResourceDefinition:
|
||||
if err := v.Get(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
crd := &apiextv1beta1.CustomResourceDefinition{}
|
||||
if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.crdBetaReady(*crd) {
|
||||
return false, nil
|
||||
}
|
||||
case *apiextv1.CustomResourceDefinition:
|
||||
if err := v.Get(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
crd := &apiextv1.CustomResourceDefinition{}
|
||||
if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.crdReady(*crd) {
|
||||
return false, nil
|
||||
}
|
||||
case *appsv1.StatefulSet, *appsv1beta1.StatefulSet, *appsv1beta2.StatefulSet:
|
||||
sts, err := w.c.AppsV1().StatefulSets(v.Namespace).Get(context.Background(), v.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !w.statefulSetReady(sts) {
|
||||
return false, nil
|
||||
}
|
||||
case *corev1.ReplicationController, *extensionsv1beta1.ReplicaSet, *appsv1beta2.ReplicaSet, *appsv1.ReplicaSet:
|
||||
ok, err = w.podsReadyForObject(v.Namespace, value)
|
||||
}
|
||||
if !ok || err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (w *waiter) podsReadyForObject(namespace string, obj runtime.Object) (bool, error) {
|
||||
pods, err := w.podsforObject(namespace, obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, pod := range pods {
|
||||
if !w.isPodReady(&pod) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (w *waiter) podsforObject(namespace string, obj runtime.Object) ([]corev1.Pod, error) {
|
||||
selector, err := SelectorsForObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := getPods(w.c, namespace, selector.String())
|
||||
return list, err
|
||||
}
|
||||
|
||||
// isPodReady returns true if a pod is ready; false otherwise.
|
||||
func (w *waiter) isPodReady(pod *corev1.Pod) bool {
|
||||
for _, c := range pod.Status.Conditions {
|
||||
if c.Type == corev1.PodReady && c.Status == corev1.ConditionTrue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
w.log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName())
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *waiter) serviceReady(s *corev1.Service) bool {
|
||||
// ExternalName Services are external to cluster so helm shouldn't be checking to see if they're 'ready' (i.e. have an IP Set)
|
||||
if s.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
return true
|
||||
}
|
||||
|
||||
// Make sure the service is not explicitly set to "None" before checking the IP
|
||||
if s.Spec.ClusterIP != corev1.ClusterIPNone && s.Spec.ClusterIP == "" {
|
||||
w.log("Service does not have cluster IP address: %s/%s", s.GetNamespace(), s.GetName())
|
||||
return false
|
||||
}
|
||||
|
||||
// This checks if the service has a LoadBalancer and that balancer has an Ingress defined
|
||||
if s.Spec.Type == corev1.ServiceTypeLoadBalancer {
|
||||
// do not wait when at least 1 external IP is set
|
||||
if len(s.Spec.ExternalIPs) > 0 {
|
||||
w.log("Service %s/%s has external IP addresses (%v), marking as ready", s.GetNamespace(), s.GetName(), s.Spec.ExternalIPs)
|
||||
return true
|
||||
}
|
||||
|
||||
if s.Status.LoadBalancer.Ingress == nil {
|
||||
w.log("Service does not have load balancer ingress IP address: %s/%s", s.GetNamespace(), s.GetName())
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *waiter) volumeReady(v *corev1.PersistentVolumeClaim) bool {
|
||||
if v.Status.Phase != corev1.ClaimBound {
|
||||
w.log("PersistentVolumeClaim is not bound: %s/%s", v.GetNamespace(), v.GetName())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *waiter) deploymentReady(rs *appsv1.ReplicaSet, dep *appsv1.Deployment) bool {
|
||||
expectedReady := *dep.Spec.Replicas - deploymentutil.MaxUnavailable(*dep)
|
||||
if !(rs.Status.ReadyReplicas >= expectedReady) {
|
||||
w.log("Deployment is not ready: %s/%s. %d out of %d expected pods are ready", dep.Namespace, dep.Name, rs.Status.ReadyReplicas, expectedReady)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *waiter) daemonSetReady(ds *appsv1.DaemonSet) bool {
|
||||
// If the update strategy is not a rolling update, there will be nothing to wait for
|
||||
if ds.Spec.UpdateStrategy.Type != appsv1.RollingUpdateDaemonSetStrategyType {
|
||||
return true
|
||||
}
|
||||
|
||||
// Make sure all the updated pods have been scheduled
|
||||
if ds.Status.UpdatedNumberScheduled != ds.Status.DesiredNumberScheduled {
|
||||
w.log("DaemonSet is not ready: %s/%s. %d out of %d expected pods have been scheduled", ds.Namespace, ds.Name, ds.Status.UpdatedNumberScheduled, ds.Status.DesiredNumberScheduled)
|
||||
return false
|
||||
}
|
||||
maxUnavailable, err := intstr.GetValueFromIntOrPercent(ds.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable, int(ds.Status.DesiredNumberScheduled), true)
|
||||
if err != nil {
|
||||
// If for some reason the value is invalid, set max unavailable to the
|
||||
// number of desired replicas. This is the same behavior as the
|
||||
// `MaxUnavailable` function in deploymentutil
|
||||
maxUnavailable = int(ds.Status.DesiredNumberScheduled)
|
||||
}
|
||||
|
||||
expectedReady := int(ds.Status.DesiredNumberScheduled) - maxUnavailable
|
||||
if !(int(ds.Status.NumberReady) >= expectedReady) {
|
||||
w.log("DaemonSet is not ready: %s/%s. %d out of %d expected pods are ready", ds.Namespace, ds.Name, ds.Status.NumberReady, expectedReady)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Because the v1 extensions API is not available on all supported k8s versions
|
||||
// yet and because Go doesn't support generics, we need to have a duplicate
|
||||
// function to support the v1beta1 types
|
||||
func (w *waiter) crdBetaReady(crd apiextv1beta1.CustomResourceDefinition) bool {
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
switch cond.Type {
|
||||
case apiextv1beta1.Established:
|
||||
if cond.Status == apiextv1beta1.ConditionTrue {
|
||||
return true
|
||||
}
|
||||
case apiextv1beta1.NamesAccepted:
|
||||
if cond.Status == apiextv1beta1.ConditionFalse {
|
||||
// This indicates a naming conflict, but it's probably not the
|
||||
// job of this function to fail because of that. Instead,
|
||||
// we treat it as a success, since the process should be able to
|
||||
// continue.
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *waiter) crdReady(crd apiextv1.CustomResourceDefinition) bool {
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
switch cond.Type {
|
||||
case apiextv1.Established:
|
||||
if cond.Status == apiextv1.ConditionTrue {
|
||||
return true
|
||||
}
|
||||
case apiextv1.NamesAccepted:
|
||||
if cond.Status == apiextv1.ConditionFalse {
|
||||
// This indicates a naming conflict, but it's probably not the
|
||||
// job of this function to fail because of that. Instead,
|
||||
// we treat it as a success, since the process should be able to
|
||||
// continue.
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *waiter) statefulSetReady(sts *appsv1.StatefulSet) bool {
|
||||
// If the update strategy is not a rolling update, there will be nothing to wait for
|
||||
if sts.Spec.UpdateStrategy.Type != appsv1.RollingUpdateStatefulSetStrategyType {
|
||||
return true
|
||||
}
|
||||
|
||||
// Dereference all the pointers because StatefulSets like them
|
||||
var partition int
|
||||
// 1 is the default for replicas if not set
|
||||
var replicas = 1
|
||||
// For some reason, even if the update strategy is a rolling update, the
|
||||
// actual rollingUpdate field can be nil. If it is, we can safely assume
|
||||
// there is no partition value
|
||||
if sts.Spec.UpdateStrategy.RollingUpdate != nil && sts.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
|
||||
partition = int(*sts.Spec.UpdateStrategy.RollingUpdate.Partition)
|
||||
}
|
||||
if sts.Spec.Replicas != nil {
|
||||
replicas = int(*sts.Spec.Replicas)
|
||||
}
|
||||
|
||||
// Because an update strategy can use partitioning, we need to calculate the
|
||||
// number of updated replicas we should have. For example, if the replicas
|
||||
// is set to 3 and the partition is 2, we'd expect only one pod to be
|
||||
// updated
|
||||
expectedReplicas := replicas - partition
|
||||
|
||||
// Make sure all the updated pods have been scheduled
|
||||
if int(sts.Status.UpdatedReplicas) != expectedReplicas {
|
||||
w.log("StatefulSet is not ready: %s/%s. %d out of %d expected pods have been scheduled", sts.Namespace, sts.Name, sts.Status.UpdatedReplicas, expectedReplicas)
|
||||
return false
|
||||
}
|
||||
|
||||
if int(sts.Status.ReadyReplicas) != replicas {
|
||||
w.log("StatefulSet is not ready: %s/%s. %d out of %d expected pods are ready", sts.Namespace, sts.Name, sts.Status.ReadyReplicas, replicas)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getPods(client kubernetes.Interface, namespace, selector string) ([]corev1.Pod, error) {
|
||||
list, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: selector,
|
||||
})
|
||||
return list.Items, err
|
||||
}
|
||||
|
||||
// SelectorsForObject returns the pod label selector for a given object
|
||||
//
|
||||
// Modified version of https://github.com/kubernetes/kubernetes/blob/v1.14.1/pkg/kubectl/polymorphichelpers/helpers.go#L84
|
||||
func SelectorsForObject(object runtime.Object) (selector labels.Selector, err error) {
|
||||
switch t := object.(type) {
|
||||
case *extensionsv1beta1.ReplicaSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1.ReplicaSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta2.ReplicaSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *corev1.ReplicationController:
|
||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||
case *appsv1.StatefulSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta1.StatefulSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta2.StatefulSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *extensionsv1beta1.DaemonSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1.DaemonSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta2.DaemonSet:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *extensionsv1beta1.Deployment:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1.Deployment:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta1.Deployment:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *appsv1beta2.Deployment:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *batchv1.Job:
|
||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||
case *corev1.Service:
|
||||
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
|
||||
return nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
|
||||
}
|
||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("selector for %T not implemented", object)
|
||||
}
|
||||
|
||||
return selector, errors.Wrap(err, "invalid label selector")
|
||||
}
|
||||
150
vendor/k8s.io/client-go/tools/watch/informerwatcher.go
generated
vendored
Normal file
150
vendor/k8s.io/client-go/tools/watch/informerwatcher.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package watch
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func newEventProcessor(out chan<- watch.Event) *eventProcessor {
|
||||
return &eventProcessor{
|
||||
out: out,
|
||||
cond: sync.NewCond(&sync.Mutex{}),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// eventProcessor buffers events and writes them to an out chan when a reader
|
||||
// is waiting. Because of the requirement to buffer events, it synchronizes
|
||||
// input with a condition, and synchronizes output with a channels. It needs to
|
||||
// be able to yield while both waiting on an input condition and while blocked
|
||||
// on writing to the output channel.
|
||||
type eventProcessor struct {
|
||||
out chan<- watch.Event
|
||||
|
||||
cond *sync.Cond
|
||||
buff []watch.Event
|
||||
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func (e *eventProcessor) run() {
|
||||
for {
|
||||
batch := e.takeBatch()
|
||||
e.writeBatch(batch)
|
||||
if e.stopped() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventProcessor) takeBatch() []watch.Event {
|
||||
e.cond.L.Lock()
|
||||
defer e.cond.L.Unlock()
|
||||
|
||||
for len(e.buff) == 0 && !e.stopped() {
|
||||
e.cond.Wait()
|
||||
}
|
||||
|
||||
batch := e.buff
|
||||
e.buff = nil
|
||||
return batch
|
||||
}
|
||||
|
||||
func (e *eventProcessor) writeBatch(events []watch.Event) {
|
||||
for _, event := range events {
|
||||
select {
|
||||
case e.out <- event:
|
||||
case <-e.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventProcessor) push(event watch.Event) {
|
||||
e.cond.L.Lock()
|
||||
defer e.cond.L.Unlock()
|
||||
defer e.cond.Signal()
|
||||
e.buff = append(e.buff, event)
|
||||
}
|
||||
|
||||
func (e *eventProcessor) stopped() bool {
|
||||
select {
|
||||
case <-e.done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventProcessor) stop() {
|
||||
close(e.done)
|
||||
e.cond.Signal()
|
||||
}
|
||||
|
||||
// NewIndexerInformerWatcher will create an IndexerInformer and wrap it into watch.Interface
|
||||
// so you can use it anywhere where you'd have used a regular Watcher returned from Watch method.
|
||||
// it also returns a channel you can use to wait for the informers to fully shutdown.
|
||||
func NewIndexerInformerWatcher(lw cache.ListerWatcher, objType runtime.Object) (cache.Indexer, cache.Controller, watch.Interface, <-chan struct{}) {
|
||||
ch := make(chan watch.Event)
|
||||
w := watch.NewProxyWatcher(ch)
|
||||
e := newEventProcessor(ch)
|
||||
|
||||
indexer, informer := cache.NewIndexerInformer(lw, objType, 0, cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
e.push(watch.Event{
|
||||
Type: watch.Added,
|
||||
Object: obj.(runtime.Object),
|
||||
})
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
e.push(watch.Event{
|
||||
Type: watch.Modified,
|
||||
Object: new.(runtime.Object),
|
||||
})
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
staleObj, stale := obj.(cache.DeletedFinalStateUnknown)
|
||||
if stale {
|
||||
// We have no means of passing the additional information down using
|
||||
// watch API based on watch.Event but the caller can filter such
|
||||
// objects by checking if metadata.deletionTimestamp is set
|
||||
obj = staleObj
|
||||
}
|
||||
|
||||
e.push(watch.Event{
|
||||
Type: watch.Deleted,
|
||||
Object: obj.(runtime.Object),
|
||||
})
|
||||
},
|
||||
}, cache.Indexers{})
|
||||
|
||||
go e.run()
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
defer e.stop()
|
||||
informer.Run(w.StopChan())
|
||||
}()
|
||||
|
||||
return indexer, informer, w, doneCh
|
||||
}
|
||||
287
vendor/k8s.io/client-go/tools/watch/retrywatcher.go
generated
vendored
Normal file
287
vendor/k8s.io/client-go/tools/watch/retrywatcher.go
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package watch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// resourceVersionGetter is an interface used to get resource version from events.
|
||||
// We can't reuse an interface from meta otherwise it would be a cyclic dependency and we need just this one method
|
||||
type resourceVersionGetter interface {
|
||||
GetResourceVersion() string
|
||||
}
|
||||
|
||||
// RetryWatcher will make sure that in case the underlying watcher is closed (e.g. due to API timeout or etcd timeout)
|
||||
// it will get restarted from the last point without the consumer even knowing about it.
|
||||
// RetryWatcher does that by inspecting events and keeping track of resourceVersion.
|
||||
// Especially useful when using watch.UntilWithoutRetry where premature termination is causing issues and flakes.
|
||||
// Please note that this is not resilient to etcd cache not having the resource version anymore - you would need to
|
||||
// use Informers for that.
|
||||
type RetryWatcher struct {
|
||||
lastResourceVersion string
|
||||
watcherClient cache.Watcher
|
||||
resultChan chan watch.Event
|
||||
stopChan chan struct{}
|
||||
doneChan chan struct{}
|
||||
minRestartDelay time.Duration
|
||||
}
|
||||
|
||||
// NewRetryWatcher creates a new RetryWatcher.
|
||||
// It will make sure that watches gets restarted in case of recoverable errors.
|
||||
// The initialResourceVersion will be given to watch method when first called.
|
||||
func NewRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher) (*RetryWatcher, error) {
|
||||
return newRetryWatcher(initialResourceVersion, watcherClient, 1*time.Second)
|
||||
}
|
||||
|
||||
func newRetryWatcher(initialResourceVersion string, watcherClient cache.Watcher, minRestartDelay time.Duration) (*RetryWatcher, error) {
|
||||
switch initialResourceVersion {
|
||||
case "", "0":
|
||||
// TODO: revisit this if we ever get WATCH v2 where it means start "now"
|
||||
// without doing the synthetic list of objects at the beginning (see #74022)
|
||||
return nil, fmt.Errorf("initial RV %q is not supported due to issues with underlying WATCH", initialResourceVersion)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
rw := &RetryWatcher{
|
||||
lastResourceVersion: initialResourceVersion,
|
||||
watcherClient: watcherClient,
|
||||
stopChan: make(chan struct{}),
|
||||
doneChan: make(chan struct{}),
|
||||
resultChan: make(chan watch.Event, 0),
|
||||
minRestartDelay: minRestartDelay,
|
||||
}
|
||||
|
||||
go rw.receive()
|
||||
return rw, nil
|
||||
}
|
||||
|
||||
func (rw *RetryWatcher) send(event watch.Event) bool {
|
||||
// Writing to an unbuffered channel is blocking operation
|
||||
// and we need to check if stop wasn't requested while doing so.
|
||||
select {
|
||||
case rw.resultChan <- event:
|
||||
return true
|
||||
case <-rw.stopChan:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// doReceive returns true when it is done, false otherwise.
|
||||
// If it is not done the second return value holds the time to wait before calling it again.
|
||||
func (rw *RetryWatcher) doReceive() (bool, time.Duration) {
|
||||
watcher, err := rw.watcherClient.Watch(metav1.ListOptions{
|
||||
ResourceVersion: rw.lastResourceVersion,
|
||||
})
|
||||
// We are very unlikely to hit EOF here since we are just establishing the call,
|
||||
// but it may happen that the apiserver is just shutting down (e.g. being restarted)
|
||||
// This is consistent with how it is handled for informers
|
||||
switch err {
|
||||
case nil:
|
||||
break
|
||||
|
||||
case io.EOF:
|
||||
// watch closed normally
|
||||
return false, 0
|
||||
|
||||
case io.ErrUnexpectedEOF:
|
||||
klog.V(1).Infof("Watch closed with unexpected EOF: %v", err)
|
||||
return false, 0
|
||||
|
||||
default:
|
||||
msg := "Watch failed: %v"
|
||||
if net.IsProbableEOF(err) || net.IsTimeout(err) {
|
||||
klog.V(5).Infof(msg, err)
|
||||
// Retry
|
||||
return false, 0
|
||||
}
|
||||
|
||||
klog.Errorf(msg, err)
|
||||
// Retry
|
||||
return false, 0
|
||||
}
|
||||
|
||||
if watcher == nil {
|
||||
klog.Error("Watch returned nil watcher")
|
||||
// Retry
|
||||
return false, 0
|
||||
}
|
||||
|
||||
ch := watcher.ResultChan()
|
||||
defer watcher.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-rw.stopChan:
|
||||
klog.V(4).Info("Stopping RetryWatcher.")
|
||||
return true, 0
|
||||
case event, ok := <-ch:
|
||||
if !ok {
|
||||
klog.V(4).Infof("Failed to get event! Re-creating the watcher. Last RV: %s", rw.lastResourceVersion)
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// We need to inspect the event and get ResourceVersion out of it
|
||||
switch event.Type {
|
||||
case watch.Added, watch.Modified, watch.Deleted, watch.Bookmark:
|
||||
metaObject, ok := event.Object.(resourceVersionGetter)
|
||||
if !ok {
|
||||
_ = rw.send(watch.Event{
|
||||
Type: watch.Error,
|
||||
Object: &apierrors.NewInternalError(errors.New("retryWatcher: doesn't support resourceVersion")).ErrStatus,
|
||||
})
|
||||
// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
|
||||
return true, 0
|
||||
}
|
||||
|
||||
resourceVersion := metaObject.GetResourceVersion()
|
||||
if resourceVersion == "" {
|
||||
_ = rw.send(watch.Event{
|
||||
Type: watch.Error,
|
||||
Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher: object %#v doesn't support resourceVersion", event.Object)).ErrStatus,
|
||||
})
|
||||
// We have to abort here because this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
|
||||
return true, 0
|
||||
}
|
||||
|
||||
// All is fine; send the event and update lastResourceVersion
|
||||
ok = rw.send(event)
|
||||
if !ok {
|
||||
return true, 0
|
||||
}
|
||||
rw.lastResourceVersion = resourceVersion
|
||||
|
||||
continue
|
||||
|
||||
case watch.Error:
|
||||
// This round trip allows us to handle unstructured status
|
||||
errObject := apierrors.FromObject(event.Object)
|
||||
statusErr, ok := errObject.(*apierrors.StatusError)
|
||||
if !ok {
|
||||
klog.Error(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object))
|
||||
// Retry unknown errors
|
||||
return false, 0
|
||||
}
|
||||
|
||||
status := statusErr.ErrStatus
|
||||
|
||||
statusDelay := time.Duration(0)
|
||||
if status.Details != nil {
|
||||
statusDelay = time.Duration(status.Details.RetryAfterSeconds) * time.Second
|
||||
}
|
||||
|
||||
switch status.Code {
|
||||
case http.StatusGone:
|
||||
// Never retry RV too old errors
|
||||
_ = rw.send(event)
|
||||
return true, 0
|
||||
|
||||
case http.StatusGatewayTimeout, http.StatusInternalServerError:
|
||||
// Retry
|
||||
return false, statusDelay
|
||||
|
||||
default:
|
||||
// We retry by default. RetryWatcher is meant to proceed unless it is certain
|
||||
// that it can't. If we are not certain, we proceed with retry and leave it
|
||||
// up to the user to timeout if needed.
|
||||
|
||||
// Log here so we have a record of hitting the unexpected error
|
||||
// and we can whitelist some error codes if we missed any that are expected.
|
||||
klog.V(5).Info(spew.Sprintf("Retrying after unexpected error: %#+v", event.Object))
|
||||
|
||||
// Retry
|
||||
return false, statusDelay
|
||||
}
|
||||
|
||||
default:
|
||||
klog.Errorf("Failed to recognize Event type %q", event.Type)
|
||||
_ = rw.send(watch.Event{
|
||||
Type: watch.Error,
|
||||
Object: &apierrors.NewInternalError(fmt.Errorf("retryWatcher failed to recognize Event type %q", event.Type)).ErrStatus,
|
||||
})
|
||||
// We are unable to restart the watch and have to stop the loop or this might cause lastResourceVersion inconsistency by skipping a potential RV with valid data!
|
||||
return true, 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// receive reads the result from a watcher, restarting it if necessary.
|
||||
func (rw *RetryWatcher) receive() {
|
||||
defer close(rw.doneChan)
|
||||
defer close(rw.resultChan)
|
||||
|
||||
klog.V(4).Info("Starting RetryWatcher.")
|
||||
defer klog.V(4).Info("Stopping RetryWatcher.")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go func() {
|
||||
select {
|
||||
case <-rw.stopChan:
|
||||
cancel()
|
||||
return
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// We use non sliding until so we don't introduce delays on happy path when WATCH call
|
||||
// timeouts or gets closed and we need to reestablish it while also avoiding hot loops.
|
||||
wait.NonSlidingUntilWithContext(ctx, func(ctx context.Context) {
|
||||
done, retryAfter := rw.doReceive()
|
||||
if done {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(retryAfter)
|
||||
|
||||
klog.V(4).Infof("Restarting RetryWatcher at RV=%q", rw.lastResourceVersion)
|
||||
}, rw.minRestartDelay)
|
||||
}
|
||||
|
||||
// ResultChan implements Interface.
|
||||
func (rw *RetryWatcher) ResultChan() <-chan watch.Event {
|
||||
return rw.resultChan
|
||||
}
|
||||
|
||||
// Stop implements Interface.
|
||||
func (rw *RetryWatcher) Stop() {
|
||||
close(rw.stopChan)
|
||||
}
|
||||
|
||||
// Done allows the caller to be notified when Retry watcher stops.
|
||||
func (rw *RetryWatcher) Done() <-chan struct{} {
|
||||
return rw.doneChan
|
||||
}
|
||||
236
vendor/k8s.io/client-go/tools/watch/until.go
generated
vendored
Normal file
236
vendor/k8s.io/client-go/tools/watch/until.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package watch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// PreconditionFunc returns true if the condition has been reached, false if it has not been reached yet,
|
||||
// or an error if the condition failed or detected an error state.
|
||||
type PreconditionFunc func(store cache.Store) (bool, error)
|
||||
|
||||
// ConditionFunc returns true if the condition has been reached, false if it has not been reached yet,
|
||||
// or an error if the condition cannot be checked and should terminate. In general, it is better to define
|
||||
// level driven conditions over edge driven conditions (pod has ready=true, vs pod modified and ready changed
|
||||
// from false to true).
|
||||
type ConditionFunc func(event watch.Event) (bool, error)
|
||||
|
||||
// ErrWatchClosed is returned when the watch channel is closed before timeout in UntilWithoutRetry.
|
||||
var ErrWatchClosed = errors.New("watch closed before UntilWithoutRetry timeout")
|
||||
|
||||
// UntilWithoutRetry reads items from the watch until each provided condition succeeds, and then returns the last watch
|
||||
// encountered. The first condition that returns an error terminates the watch (and the event is also returned).
|
||||
// If no event has been received, the returned event will be nil.
|
||||
// Conditions are satisfied sequentially so as to provide a useful primitive for higher level composition.
|
||||
// Waits until context deadline or until context is canceled.
|
||||
//
|
||||
// Warning: Unless you have a very specific use case (probably a special Watcher) don't use this function!!!
|
||||
// Warning: This will fail e.g. on API timeouts and/or 'too old resource version' error.
|
||||
// Warning: You are most probably looking for a function *Until* or *UntilWithSync* below,
|
||||
// Warning: solving such issues.
|
||||
// TODO: Consider making this function private to prevent misuse when the other occurrences in our codebase are gone.
|
||||
func UntilWithoutRetry(ctx context.Context, watcher watch.Interface, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
ch := watcher.ResultChan()
|
||||
defer watcher.Stop()
|
||||
var lastEvent *watch.Event
|
||||
for _, condition := range conditions {
|
||||
// check the next condition against the previous event and short circuit waiting for the next watch
|
||||
if lastEvent != nil {
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
continue
|
||||
}
|
||||
}
|
||||
ConditionSucceeded:
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-ch:
|
||||
if !ok {
|
||||
return lastEvent, ErrWatchClosed
|
||||
}
|
||||
lastEvent = &event
|
||||
|
||||
done, err := condition(event)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
break ConditionSucceeded
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return lastEvent, wait.ErrWaitTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastEvent, nil
|
||||
}
|
||||
|
||||
// Until wraps the watcherClient's watch function with RetryWatcher making sure that watcher gets restarted in case of errors.
|
||||
// The initialResourceVersion will be given to watch method when first called. It shall not be "" or "0"
|
||||
// given the underlying WATCH call issues (#74022). If you want the initial list ("", "0") done for you use ListWatchUntil instead.
|
||||
// Remaining behaviour is identical to function UntilWithoutRetry. (See above.)
|
||||
// Until can deal with API timeouts and lost connections.
|
||||
// It guarantees you to see all events and in the order they happened.
|
||||
// Due to this guarantee there is no way it can deal with 'Resource version too old error'. It will fail in this case.
|
||||
// (See `UntilWithSync` if you'd prefer to recover from all the errors including RV too old by re-listing
|
||||
// those items. In normal code you should care about being level driven so you'd not care about not seeing all the edges.)
|
||||
// The most frequent usage for Until would be a test where you want to verify exact order of events ("edges").
|
||||
func Until(ctx context.Context, initialResourceVersion string, watcherClient cache.Watcher, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
w, err := NewRetryWatcher(initialResourceVersion, watcherClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return UntilWithoutRetry(ctx, w, conditions...)
|
||||
}
|
||||
|
||||
// UntilWithSync creates an informer from lw, optionally checks precondition when the store is synced,
|
||||
// and watches the output until each provided condition succeeds, in a way that is identical
|
||||
// to function UntilWithoutRetry. (See above.)
|
||||
// UntilWithSync can deal with all errors like API timeout, lost connections and 'Resource version too old'.
|
||||
// It is the only function that can recover from 'Resource version too old', Until and UntilWithoutRetry will
|
||||
// just fail in that case. On the other hand it can't provide you with guarantees as strong as using simple
|
||||
// Watch method with Until. It can skip some intermediate events in case of watch function failing but it will
|
||||
// re-list to recover and you always get an event, if there has been a change, after recovery.
|
||||
// Also with the current implementation based on DeltaFIFO, order of the events you receive is guaranteed only for
|
||||
// particular object, not between more of them even it's the same resource.
|
||||
// The most frequent usage would be a command that needs to watch the "state of the world" and should't fail, like:
|
||||
// waiting for object reaching a state, "small" controllers, ...
|
||||
func UntilWithSync(ctx context.Context, lw cache.ListerWatcher, objType runtime.Object, precondition PreconditionFunc, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
indexer, informer, watcher, done := NewIndexerInformerWatcher(lw, objType)
|
||||
// We need to wait for the internal informers to fully stop so it's easier to reason about
|
||||
// and it works with non-thread safe clients.
|
||||
defer func() { <-done }()
|
||||
// Proxy watcher can be stopped multiple times so it's fine to use defer here to cover alternative branches and
|
||||
// let UntilWithoutRetry to stop it
|
||||
defer watcher.Stop()
|
||||
|
||||
if precondition != nil {
|
||||
if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) {
|
||||
return nil, fmt.Errorf("UntilWithSync: unable to sync caches: %v", ctx.Err())
|
||||
}
|
||||
|
||||
done, err := precondition(indexer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if done {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return UntilWithoutRetry(ctx, watcher, conditions...)
|
||||
}
|
||||
|
||||
// ContextWithOptionalTimeout wraps context.WithTimeout and handles infinite timeouts expressed as 0 duration.
|
||||
func ContextWithOptionalTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
if timeout < 0 {
|
||||
// This should be handled in validation
|
||||
klog.Errorf("Timeout for context shall not be negative!")
|
||||
timeout = 0
|
||||
}
|
||||
|
||||
if timeout == 0 {
|
||||
return context.WithCancel(parent)
|
||||
}
|
||||
|
||||
return context.WithTimeout(parent, timeout)
|
||||
}
|
||||
|
||||
// ListWatchUntil first lists objects, converts them into synthetic ADDED events
|
||||
// and checks conditions for those synthetic events. If the conditions have not been reached so far
|
||||
// it continues by calling Until which establishes a watch from resourceVersion of the list call
|
||||
// to evaluate those conditions based on new events.
|
||||
// ListWatchUntil provides the same guarantees as Until and replaces the old WATCH from RV "" (or "0")
|
||||
// which was mixing list and watch calls internally and having severe design issues. (see #74022)
|
||||
// There is no resourceVersion order guarantee for the initial list and those synthetic events.
|
||||
func ListWatchUntil(ctx context.Context, lw cache.ListerWatcher, conditions ...ConditionFunc) (*watch.Event, error) {
|
||||
if len(conditions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
list, err := lw.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
initialItems, err := meta.ExtractList(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use the initial items as simulated "adds"
|
||||
var lastEvent *watch.Event
|
||||
currIndex := 0
|
||||
passedConditions := 0
|
||||
for _, condition := range conditions {
|
||||
// check the next condition against the previous event and short circuit waiting for the next watch
|
||||
if lastEvent != nil {
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ConditionSucceeded:
|
||||
for currIndex < len(initialItems) {
|
||||
lastEvent = &watch.Event{Type: watch.Added, Object: initialItems[currIndex]}
|
||||
currIndex++
|
||||
|
||||
done, err := condition(*lastEvent)
|
||||
if err != nil {
|
||||
return lastEvent, err
|
||||
}
|
||||
if done {
|
||||
passedConditions = passedConditions + 1
|
||||
break ConditionSucceeded
|
||||
}
|
||||
}
|
||||
}
|
||||
if passedConditions == len(conditions) {
|
||||
return lastEvent, nil
|
||||
}
|
||||
remainingConditions := conditions[passedConditions:]
|
||||
|
||||
metaObj, err := meta.ListAccessor(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currResourceVersion := metaObj.GetResourceVersion()
|
||||
|
||||
return Until(ctx, currResourceVersion, lw, remainingConditions...)
|
||||
}
|
||||
28
vendor/modules.txt
vendored
28
vendor/modules.txt
vendored
@@ -183,6 +183,8 @@ github.com/fatih/structs
|
||||
github.com/fsnotify/fsnotify
|
||||
# github.com/ghodss/yaml v1.0.0 => github.com/ghodss/yaml v1.0.0
|
||||
github.com/ghodss/yaml
|
||||
# github.com/go-errors/errors v1.0.1 => github.com/go-errors/errors v1.0.1
|
||||
github.com/go-errors/errors
|
||||
# github.com/go-kit/kit v0.10.0 => github.com/go-kit/kit v0.10.0
|
||||
github.com/go-kit/kit/log
|
||||
github.com/go-kit/kit/log/level
|
||||
@@ -310,7 +312,7 @@ github.com/hashicorp/hcl/hcl/token
|
||||
github.com/hashicorp/hcl/json/parser
|
||||
github.com/hashicorp/hcl/json/scanner
|
||||
github.com/hashicorp/hcl/json/token
|
||||
# github.com/imdario/mergo v0.3.9 => github.com/imdario/mergo v0.3.9
|
||||
# github.com/imdario/mergo v0.3.12 => github.com/imdario/mergo v0.3.9
|
||||
github.com/imdario/mergo
|
||||
# github.com/inconshreveable/mousetrap v1.0.0 => github.com/inconshreveable/mousetrap v1.0.0
|
||||
github.com/inconshreveable/mousetrap
|
||||
@@ -567,7 +569,7 @@ github.com/prometheus/prometheus/util/testutil
|
||||
github.com/rcrowley/go-metrics
|
||||
# github.com/russross/blackfriday v1.5.2 => github.com/russross/blackfriday v1.5.2
|
||||
github.com/russross/blackfriday
|
||||
# github.com/sergi/go-diff v1.0.0 => github.com/sergi/go-diff v1.0.0
|
||||
# github.com/sergi/go-diff v1.1.0 => github.com/sergi/go-diff v1.0.0
|
||||
github.com/sergi/go-diff/diffmatchpatch
|
||||
# github.com/sirupsen/logrus v1.6.0 => github.com/sirupsen/logrus v1.4.2
|
||||
github.com/sirupsen/logrus
|
||||
@@ -909,7 +911,7 @@ gopkg.in/src-d/go-git.v4/utils/merkletrie/noder
|
||||
gopkg.in/tomb.v1
|
||||
# gopkg.in/warnings.v0 v0.1.2 => gopkg.in/warnings.v0 v0.1.2
|
||||
gopkg.in/warnings.v0
|
||||
# gopkg.in/yaml.v2 v2.3.0 => gopkg.in/yaml.v2 v2.3.0
|
||||
# gopkg.in/yaml.v2 v2.4.0 => gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v2
|
||||
# gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 => gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
gopkg.in/yaml.v3
|
||||
@@ -924,6 +926,7 @@ helm.sh/helm/v3/internal/fileutil
|
||||
helm.sh/helm/v3/internal/ignore
|
||||
helm.sh/helm/v3/internal/sympath
|
||||
helm.sh/helm/v3/internal/third_party/dep/fs
|
||||
helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util
|
||||
helm.sh/helm/v3/internal/tlsutil
|
||||
helm.sh/helm/v3/internal/urlutil
|
||||
helm.sh/helm/v3/internal/version
|
||||
@@ -933,6 +936,7 @@ helm.sh/helm/v3/pkg/cli
|
||||
helm.sh/helm/v3/pkg/getter
|
||||
helm.sh/helm/v3/pkg/helmpath
|
||||
helm.sh/helm/v3/pkg/helmpath/xdg
|
||||
helm.sh/helm/v3/pkg/kube
|
||||
helm.sh/helm/v3/pkg/plugin
|
||||
helm.sh/helm/v3/pkg/provenance
|
||||
helm.sh/helm/v3/pkg/release
|
||||
@@ -1486,6 +1490,7 @@ k8s.io/client-go/tools/record
|
||||
k8s.io/client-go/tools/record/util
|
||||
k8s.io/client-go/tools/reference
|
||||
k8s.io/client-go/tools/remotecommand
|
||||
k8s.io/client-go/tools/watch
|
||||
k8s.io/client-go/transport
|
||||
k8s.io/client-go/transport/spdy
|
||||
k8s.io/client-go/util/cert
|
||||
@@ -1667,6 +1672,23 @@ sigs.k8s.io/kubefed/pkg/kubefedctl/options
|
||||
sigs.k8s.io/kubefed/pkg/kubefedctl/util
|
||||
sigs.k8s.io/kubefed/pkg/metrics
|
||||
# sigs.k8s.io/kustomize v2.0.3+incompatible => sigs.k8s.io/kustomize v2.0.3+incompatible
|
||||
# sigs.k8s.io/kustomize/api v0.8.6 => sigs.k8s.io/kustomize/api v0.8.6
|
||||
sigs.k8s.io/kustomize/api/resid
|
||||
sigs.k8s.io/kustomize/api/types
|
||||
# sigs.k8s.io/kustomize/kyaml v0.10.17 => sigs.k8s.io/kustomize/kyaml v0.10.17
|
||||
sigs.k8s.io/kustomize/kyaml/errors
|
||||
sigs.k8s.io/kustomize/kyaml/openapi
|
||||
sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi
|
||||
sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204
|
||||
sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi
|
||||
sigs.k8s.io/kustomize/kyaml/sets
|
||||
sigs.k8s.io/kustomize/kyaml/yaml
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation
|
||||
sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field
|
||||
sigs.k8s.io/kustomize/pkg/commands/build
|
||||
sigs.k8s.io/kustomize/pkg/constants
|
||||
sigs.k8s.io/kustomize/pkg/expansion
|
||||
|
||||
201
vendor/sigs.k8s.io/kustomize/api/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/kustomize/api/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
232
vendor/sigs.k8s.io/kustomize/api/resid/gvk.go
generated
vendored
Normal file
232
vendor/sigs.k8s.io/kustomize/api/resid/gvk.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Gvk identifies a Kubernetes API type.
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md
|
||||
type Gvk struct {
|
||||
Group string `json:"group,omitempty" yaml:"group,omitempty"`
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// FromKind makes a Gvk with only the kind specified.
|
||||
func FromKind(k string) Gvk {
|
||||
return Gvk{
|
||||
Kind: k,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseGroupVersion parses a KRM metadata apiVersion field.
|
||||
func ParseGroupVersion(apiVersion string) (group, version string) {
|
||||
if i := strings.Index(apiVersion, "/"); i > -1 {
|
||||
return apiVersion[:i], apiVersion[i+1:]
|
||||
}
|
||||
return "", apiVersion
|
||||
}
|
||||
|
||||
// GvkFromString makes a Gvk from the output of Gvk.String().
|
||||
func GvkFromString(s string) Gvk {
|
||||
values := strings.Split(s, fieldSep)
|
||||
if len(values) != 3 {
|
||||
// ...then the string didn't come from Gvk.String().
|
||||
return Gvk{
|
||||
Group: noGroup,
|
||||
Version: noVersion,
|
||||
Kind: noKind,
|
||||
}
|
||||
}
|
||||
g := values[0]
|
||||
if g == noGroup {
|
||||
g = ""
|
||||
}
|
||||
v := values[1]
|
||||
if v == noVersion {
|
||||
v = ""
|
||||
}
|
||||
k := values[2]
|
||||
if k == noKind {
|
||||
k = ""
|
||||
}
|
||||
return Gvk{
|
||||
Group: g,
|
||||
Version: v,
|
||||
Kind: k,
|
||||
}
|
||||
}
|
||||
|
||||
// Values that are brief but meaningful in logs.
|
||||
const (
|
||||
noGroup = "~G"
|
||||
noVersion = "~V"
|
||||
noKind = "~K"
|
||||
fieldSep = "_"
|
||||
)
|
||||
|
||||
// String returns a string representation of the GVK.
|
||||
func (x Gvk) String() string {
|
||||
g := x.Group
|
||||
if g == "" {
|
||||
g = noGroup
|
||||
}
|
||||
v := x.Version
|
||||
if v == "" {
|
||||
v = noVersion
|
||||
}
|
||||
k := x.Kind
|
||||
if k == "" {
|
||||
k = noKind
|
||||
}
|
||||
return strings.Join([]string{g, v, k}, fieldSep)
|
||||
}
|
||||
|
||||
// ApiVersion returns the combination of Group and Version
|
||||
func (x Gvk) ApiVersion() string {
|
||||
if x.Group == "" {
|
||||
return x.Version
|
||||
}
|
||||
return x.Group + "/" + x.Version
|
||||
}
|
||||
|
||||
// StringWoEmptyField returns a string representation of the GVK. Non-exist
|
||||
// fields will be omitted.
|
||||
func (x Gvk) StringWoEmptyField() string {
|
||||
var s []string
|
||||
if x.Group != "" {
|
||||
s = append(s, x.Group)
|
||||
}
|
||||
if x.Version != "" {
|
||||
s = append(s, x.Version)
|
||||
}
|
||||
if x.Kind != "" {
|
||||
s = append(s, x.Kind)
|
||||
}
|
||||
return strings.Join(s, fieldSep)
|
||||
}
|
||||
|
||||
// Equals returns true if the Gvk's have equal fields.
|
||||
func (x Gvk) Equals(o Gvk) bool {
|
||||
return x.Group == o.Group && x.Version == o.Version && x.Kind == o.Kind
|
||||
}
|
||||
|
||||
// An attempt to order things to help k8s, e.g.
|
||||
// a Service should come before things that refer to it.
|
||||
// Namespace should be first.
|
||||
// In some cases order just specified to provide determinism.
|
||||
var orderFirst = []string{
|
||||
"Namespace",
|
||||
"ResourceQuota",
|
||||
"StorageClass",
|
||||
"CustomResourceDefinition",
|
||||
"ServiceAccount",
|
||||
"PodSecurityPolicy",
|
||||
"Role",
|
||||
"ClusterRole",
|
||||
"RoleBinding",
|
||||
"ClusterRoleBinding",
|
||||
"ConfigMap",
|
||||
"Secret",
|
||||
"Endpoints",
|
||||
"Service",
|
||||
"LimitRange",
|
||||
"PriorityClass",
|
||||
"PersistentVolume",
|
||||
"PersistentVolumeClaim",
|
||||
"Deployment",
|
||||
"StatefulSet",
|
||||
"CronJob",
|
||||
"PodDisruptionBudget",
|
||||
}
|
||||
var orderLast = []string{
|
||||
"MutatingWebhookConfiguration",
|
||||
"ValidatingWebhookConfiguration",
|
||||
}
|
||||
var typeOrders = func() map[string]int {
|
||||
m := map[string]int{}
|
||||
for i, n := range orderFirst {
|
||||
m[n] = -len(orderFirst) + i
|
||||
}
|
||||
for i, n := range orderLast {
|
||||
m[n] = 1 + i
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// IsLessThan returns true if self is less than the argument.
|
||||
func (x Gvk) IsLessThan(o Gvk) bool {
|
||||
indexI := typeOrders[x.Kind]
|
||||
indexJ := typeOrders[o.Kind]
|
||||
if indexI != indexJ {
|
||||
return indexI < indexJ
|
||||
}
|
||||
return x.String() < o.String()
|
||||
}
|
||||
|
||||
// IsSelected returns true if `selector` selects `x`; otherwise, false.
|
||||
// If `selector` and `x` are the same, return true.
|
||||
// If `selector` is nil, it is considered a wildcard match, returning true.
|
||||
// If selector fields are empty, they are considered wildcards matching
|
||||
// anything in the corresponding fields, e.g.
|
||||
//
|
||||
// this item:
|
||||
// <Group: "extensions", Version: "v1beta1", Kind: "Deployment">
|
||||
//
|
||||
// is selected by
|
||||
// <Group: "", Version: "", Kind: "Deployment">
|
||||
//
|
||||
// but rejected by
|
||||
// <Group: "apps", Version: "", Kind: "Deployment">
|
||||
//
|
||||
func (x Gvk) IsSelected(selector *Gvk) bool {
|
||||
if selector == nil {
|
||||
return true
|
||||
}
|
||||
if len(selector.Group) > 0 {
|
||||
if x.Group != selector.Group {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(selector.Version) > 0 {
|
||||
if x.Version != selector.Version {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(selector.Kind) > 0 {
|
||||
if x.Kind != selector.Kind {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// toKyamlTypeMeta returns a yaml.TypeMeta from x's information.
|
||||
func (x Gvk) toKyamlTypeMeta() yaml.TypeMeta {
|
||||
var apiVersion strings.Builder
|
||||
if x.Group != "" {
|
||||
apiVersion.WriteString(x.Group)
|
||||
apiVersion.WriteString("/")
|
||||
}
|
||||
apiVersion.WriteString(x.Version)
|
||||
return yaml.TypeMeta{
|
||||
APIVersion: apiVersion.String(),
|
||||
Kind: x.Kind,
|
||||
}
|
||||
}
|
||||
|
||||
// IsNamespaceableKind returns true if x is a namespaceable Gvk,
|
||||
// e.g. instances of Pod and Deployment are namespaceable,
|
||||
// but instances of Node and Namespace are not namespaceable.
|
||||
// Alternative name for this method: IsNotClusterScoped.
|
||||
// Implements https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace
|
||||
func (x Gvk) IsNamespaceableKind() bool {
|
||||
isNamespaceScoped, found := openapi.IsNamespaceScoped(x.toKyamlTypeMeta())
|
||||
return !found || isNamespaceScoped
|
||||
}
|
||||
127
vendor/sigs.k8s.io/kustomize/api/resid/resid.go
generated
vendored
Normal file
127
vendor/sigs.k8s.io/kustomize/api/resid/resid.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ResId is an identifier of a k8s resource object.
|
||||
type ResId struct {
|
||||
// Gvk of the resource.
|
||||
Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Name of the resource before transformation.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Namespace the resource belongs to.
|
||||
// An untransformed resource has no namespace.
|
||||
// A fully transformed resource has the namespace
|
||||
// from the top most overlay.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// NewResIdWithNamespace creates new ResId
|
||||
// in a given namespace.
|
||||
func NewResIdWithNamespace(k Gvk, n, ns string) ResId {
|
||||
return ResId{Gvk: k, Name: n, Namespace: ns}
|
||||
}
|
||||
|
||||
// NewResId creates new ResId.
|
||||
func NewResId(k Gvk, n string) ResId {
|
||||
return ResId{Gvk: k, Name: n}
|
||||
}
|
||||
|
||||
// NewResIdKindOnly creates a new ResId.
|
||||
func NewResIdKindOnly(k string, n string) ResId {
|
||||
return ResId{Gvk: FromKind(k), Name: n}
|
||||
}
|
||||
|
||||
const (
|
||||
noNamespace = "~X"
|
||||
noName = "~N"
|
||||
separator = "|"
|
||||
TotallyNotANamespace = "_non_namespaceable_"
|
||||
DefaultNamespace = "default"
|
||||
)
|
||||
|
||||
// String of ResId based on GVK, name and prefix
|
||||
func (id ResId) String() string {
|
||||
ns := id.Namespace
|
||||
if ns == "" {
|
||||
ns = noNamespace
|
||||
}
|
||||
nm := id.Name
|
||||
if nm == "" {
|
||||
nm = noName
|
||||
}
|
||||
return strings.Join(
|
||||
[]string{id.Gvk.String(), ns, nm}, separator)
|
||||
}
|
||||
|
||||
func FromString(s string) ResId {
|
||||
values := strings.Split(s, separator)
|
||||
g := GvkFromString(values[0])
|
||||
|
||||
ns := values[1]
|
||||
if ns == noNamespace {
|
||||
ns = ""
|
||||
}
|
||||
nm := values[2]
|
||||
if nm == noName {
|
||||
nm = ""
|
||||
}
|
||||
return ResId{
|
||||
Gvk: g,
|
||||
Namespace: ns,
|
||||
Name: nm,
|
||||
}
|
||||
}
|
||||
|
||||
// GvknString of ResId based on GVK and name
|
||||
func (id ResId) GvknString() string {
|
||||
return id.Gvk.String() + separator + id.Name
|
||||
}
|
||||
|
||||
// GvknEquals returns true if the other id matches
|
||||
// Group/Version/Kind/name.
|
||||
func (id ResId) GvknEquals(o ResId) bool {
|
||||
return id.Name == o.Name && id.Gvk.Equals(o.Gvk)
|
||||
}
|
||||
|
||||
// Equals returns true if the other id matches
|
||||
// namespace/Group/Version/Kind/name.
|
||||
func (id ResId) Equals(o ResId) bool {
|
||||
return id.IsNsEquals(o) && id.GvknEquals(o)
|
||||
}
|
||||
|
||||
// IsNsEquals returns true if the id is in
|
||||
// the same effective namespace.
|
||||
func (id ResId) IsNsEquals(o ResId) bool {
|
||||
return id.EffectiveNamespace() == o.EffectiveNamespace()
|
||||
}
|
||||
|
||||
// IsInDefaultNs returns true if id is a namespaceable
|
||||
// ResId and the Namespace is either not set or set
|
||||
// to DefaultNamespace.
|
||||
func (id ResId) IsInDefaultNs() bool {
|
||||
return id.IsNamespaceableKind() && id.isPutativelyDefaultNs()
|
||||
}
|
||||
|
||||
func (id ResId) isPutativelyDefaultNs() bool {
|
||||
return id.Namespace == "" || id.Namespace == DefaultNamespace
|
||||
}
|
||||
|
||||
// EffectiveNamespace returns a non-ambiguous, non-empty
|
||||
// namespace for use in reporting and equality tests.
|
||||
func (id ResId) EffectiveNamespace() string {
|
||||
// The order of these checks matters.
|
||||
if !id.IsNamespaceableKind() {
|
||||
return TotallyNotANamespace
|
||||
}
|
||||
if id.isPutativelyDefaultNs() {
|
||||
return DefaultNamespace
|
||||
}
|
||||
return id.Namespace
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/builtinpluginloadingoptions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/builtinpluginloadingoptions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=BuiltinPluginLoadingOptions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[BploUndefined-0]
|
||||
_ = x[BploUseStaticallyLinked-1]
|
||||
_ = x[BploLoadFromFileSys-2]
|
||||
}
|
||||
|
||||
const _BuiltinPluginLoadingOptions_name = "BploUndefinedBploUseStaticallyLinkedBploLoadFromFileSys"
|
||||
|
||||
var _BuiltinPluginLoadingOptions_index = [...]uint8{0, 13, 36, 55}
|
||||
|
||||
func (i BuiltinPluginLoadingOptions) String() string {
|
||||
if i < 0 || i >= BuiltinPluginLoadingOptions(len(_BuiltinPluginLoadingOptions_index)-1) {
|
||||
return "BuiltinPluginLoadingOptions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BuiltinPluginLoadingOptions_name[_BuiltinPluginLoadingOptions_index[i]:_BuiltinPluginLoadingOptions_index[i+1]]
|
||||
}
|
||||
10
vendor/sigs.k8s.io/kustomize/api/types/configmapargs.go
generated
vendored
Normal file
10
vendor/sigs.k8s.io/kustomize/api/types/configmapargs.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ConfigMapArgs contains the metadata of how to generate a configmap.
|
||||
type ConfigMapArgs struct {
|
||||
// GeneratorArgs for the configmap.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
}
|
||||
9
vendor/sigs.k8s.io/kustomize/api/types/doc.go
generated
vendored
Normal file
9
vendor/sigs.k8s.io/kustomize/api/types/doc.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package types holds the definition of the kustomization struct and
|
||||
// supporting structs. It's the k8s API conformant object that describes
|
||||
// a set of generation and transformation operations to create and/or
|
||||
// modify k8s resources.
|
||||
// A kustomization file is a serialization of this struct.
|
||||
package types
|
||||
33
vendor/sigs.k8s.io/kustomize/api/types/erronlybuiltinpluginsallowed.go
generated
vendored
Normal file
33
vendor/sigs.k8s.io/kustomize/api/types/erronlybuiltinpluginsallowed.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errOnlyBuiltinPluginsAllowed struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *errOnlyBuiltinPluginsAllowed) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"external plugins disabled; unable to load external plugin '%s'",
|
||||
e.name)
|
||||
}
|
||||
|
||||
func NewErrOnlyBuiltinPluginsAllowed(n string) *errOnlyBuiltinPluginsAllowed {
|
||||
return &errOnlyBuiltinPluginsAllowed{name: n}
|
||||
}
|
||||
|
||||
func IsErrOnlyBuiltinPluginsAllowed(err error) bool {
|
||||
_, ok := err.(*errOnlyBuiltinPluginsAllowed)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errOnlyBuiltinPluginsAllowed)
|
||||
return ok
|
||||
}
|
||||
40
vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/api/types/errunabletofind.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type errUnableToFind struct {
|
||||
// What are we unable to find?
|
||||
what string
|
||||
// What things did we try?
|
||||
attempts []Pair
|
||||
}
|
||||
|
||||
func (e *errUnableToFind) Error() string {
|
||||
var m []string
|
||||
for _, p := range e.attempts {
|
||||
m = append(m, "('"+p.Value+"'; "+p.Key+")")
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"unable to find %s - tried: %s", e.what, strings.Join(m, ", "))
|
||||
}
|
||||
|
||||
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {
|
||||
return &errUnableToFind{what: w, attempts: a}
|
||||
}
|
||||
|
||||
func IsErrUnableToFind(err error) bool {
|
||||
_, ok := err.(*errUnableToFind)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
_, ok = errors.Cause(err).(*errUnableToFind)
|
||||
return ok
|
||||
}
|
||||
91
vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go
generated
vendored
Normal file
91
vendor/sigs.k8s.io/kustomize/api/types/fieldspec.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// FieldSpec completely specifies a kustomizable field in a k8s API object.
|
||||
// It helps define the operands of transformations.
|
||||
//
|
||||
// For example, a directive to add a common label to objects
|
||||
// will need to know that a 'Deployment' object (in API group
|
||||
// 'apps', any version) can have labels at field path
|
||||
// 'spec/template/metadata/labels', and further that it is OK
|
||||
// (or not OK) to add that field path to the object if the
|
||||
// field path doesn't exist already.
|
||||
//
|
||||
// This would look like
|
||||
// {
|
||||
// group: apps
|
||||
// kind: Deployment
|
||||
// path: spec/template/metadata/labels
|
||||
// create: true
|
||||
// }
|
||||
type FieldSpec struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
CreateIfNotPresent bool `json:"create,omitempty" yaml:"create,omitempty"`
|
||||
}
|
||||
|
||||
func (fs FieldSpec) String() string {
|
||||
return fmt.Sprintf(
|
||||
"%s:%v:%s", fs.Gvk.String(), fs.CreateIfNotPresent, fs.Path)
|
||||
}
|
||||
|
||||
// If true, the primary key is the same, but other fields might not be.
|
||||
func (fs FieldSpec) effectivelyEquals(other FieldSpec) bool {
|
||||
return fs.IsSelected(&other.Gvk) && fs.Path == other.Path
|
||||
}
|
||||
|
||||
type FsSlice []FieldSpec
|
||||
|
||||
func (s FsSlice) Len() int { return len(s) }
|
||||
func (s FsSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s FsSlice) Less(i, j int) bool {
|
||||
return s[i].Gvk.IsLessThan(s[j].Gvk)
|
||||
}
|
||||
|
||||
// MergeAll merges the argument into this, returning the result.
|
||||
// Items already present are ignored.
|
||||
// Items that conflict (primary key matches, but remain data differs)
|
||||
// result in an error.
|
||||
func (s FsSlice) MergeAll(incoming FsSlice) (result FsSlice, err error) {
|
||||
result = s
|
||||
for _, x := range incoming {
|
||||
result, err = result.MergeOne(x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MergeOne merges the argument into this, returning the result.
|
||||
// If the item's primary key is already present, and there are no
|
||||
// conflicts, it is ignored (we don't want duplicates).
|
||||
// If there is a conflict, the merge fails.
|
||||
func (s FsSlice) MergeOne(x FieldSpec) (FsSlice, error) {
|
||||
i := s.index(x)
|
||||
if i > -1 {
|
||||
// It's already there.
|
||||
if s[i].CreateIfNotPresent != x.CreateIfNotPresent {
|
||||
return nil, fmt.Errorf("conflicting fieldspecs")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
return append(s, x), nil
|
||||
}
|
||||
|
||||
func (s FsSlice) index(fs FieldSpec) int {
|
||||
for i, x := range s {
|
||||
if x.effectivelyEquals(fs) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
54
vendor/sigs.k8s.io/kustomize/api/types/fix.go
generated
vendored
Normal file
54
vendor/sigs.k8s.io/kustomize/api/types/fix.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// FixKustomizationPreUnmarshalling modifies the raw data
|
||||
// before marshalling - e.g. changes old field names to
|
||||
// new field names.
|
||||
func FixKustomizationPreUnmarshalling(data []byte) ([]byte, error) {
|
||||
deprecatedFieldsMap := map[string]string{
|
||||
"imageTags:": "images:",
|
||||
}
|
||||
for oldname, newname := range deprecatedFieldsMap {
|
||||
pattern := regexp.MustCompile(oldname)
|
||||
data = pattern.ReplaceAll(data, []byte(newname))
|
||||
}
|
||||
doLegacy, err := useLegacyPatch(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if doLegacy {
|
||||
pattern := regexp.MustCompile("patches:")
|
||||
data = pattern.ReplaceAll(data, []byte("patchesStrategicMerge:"))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func useLegacyPatch(data []byte) (bool, error) {
|
||||
found := false
|
||||
var object map[string]interface{}
|
||||
err := yaml.Unmarshal(data, &object)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rawPatches, ok := object["patches"]; ok {
|
||||
patches, ok := rawPatches.([]interface{})
|
||||
if !ok {
|
||||
return false, err
|
||||
}
|
||||
for _, p := range patches {
|
||||
_, ok := p.(string)
|
||||
if ok {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
46
vendor/sigs.k8s.io/kustomize/api/types/genargs.go
generated
vendored
Normal file
46
vendor/sigs.k8s.io/kustomize/api/types/genargs.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GenArgs is a facade over GeneratorArgs, exposing a few readonly properties.
|
||||
type GenArgs struct {
|
||||
args *GeneratorArgs
|
||||
}
|
||||
|
||||
// NewGenArgs returns a new instance of GenArgs.
|
||||
func NewGenArgs(args *GeneratorArgs) *GenArgs {
|
||||
return &GenArgs{args: args}
|
||||
}
|
||||
|
||||
func (g *GenArgs) String() string {
|
||||
if g == nil {
|
||||
return "{nilGenArgs}"
|
||||
}
|
||||
return "{" +
|
||||
strings.Join([]string{
|
||||
"nsfx:" + strconv.FormatBool(g.ShouldAddHashSuffixToName()),
|
||||
"beh:" + g.Behavior().String()},
|
||||
",") +
|
||||
"}"
|
||||
}
|
||||
|
||||
// ShouldAddHashSuffixToName returns true if a resource
|
||||
// content hash should be appended to the name of the resource.
|
||||
func (g *GenArgs) ShouldAddHashSuffixToName() bool {
|
||||
return g.args != nil &&
|
||||
(g.args.Options == nil || !g.args.Options.DisableNameSuffixHash)
|
||||
}
|
||||
|
||||
// Behavior returns Behavior field of GeneratorArgs
|
||||
func (g *GenArgs) Behavior() GenerationBehavior {
|
||||
if g.args == nil {
|
||||
return BehaviorUnspecified
|
||||
}
|
||||
return NewGenerationBehavior(g.args.Behavior)
|
||||
}
|
||||
46
vendor/sigs.k8s.io/kustomize/api/types/generationbehavior.go
generated
vendored
Normal file
46
vendor/sigs.k8s.io/kustomize/api/types/generationbehavior.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GenerationBehavior specifies generation behavior of configmaps, secrets and maybe other resources.
|
||||
type GenerationBehavior int
|
||||
|
||||
const (
|
||||
// BehaviorUnspecified is an Unspecified behavior; typically treated as a Create.
|
||||
BehaviorUnspecified GenerationBehavior = iota
|
||||
// BehaviorCreate makes a new resource.
|
||||
BehaviorCreate
|
||||
// BehaviorReplace replaces a resource.
|
||||
BehaviorReplace
|
||||
// BehaviorMerge attempts to merge a new resource with an existing resource.
|
||||
BehaviorMerge
|
||||
)
|
||||
|
||||
// String converts a GenerationBehavior to a string.
|
||||
func (b GenerationBehavior) String() string {
|
||||
switch b {
|
||||
case BehaviorReplace:
|
||||
return "replace"
|
||||
case BehaviorMerge:
|
||||
return "merge"
|
||||
case BehaviorCreate:
|
||||
return "create"
|
||||
default:
|
||||
return "unspecified"
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenerationBehavior converts a string to a GenerationBehavior.
|
||||
func NewGenerationBehavior(s string) GenerationBehavior {
|
||||
switch s {
|
||||
case "replace":
|
||||
return BehaviorReplace
|
||||
case "merge":
|
||||
return BehaviorMerge
|
||||
case "create":
|
||||
return BehaviorCreate
|
||||
default:
|
||||
return BehaviorUnspecified
|
||||
}
|
||||
}
|
||||
27
vendor/sigs.k8s.io/kustomize/api/types/generatorargs.go
generated
vendored
Normal file
27
vendor/sigs.k8s.io/kustomize/api/types/generatorargs.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorArgs contains arguments common to ConfigMap and Secret generators.
|
||||
type GeneratorArgs struct {
|
||||
// Namespace for the configmap, optional
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// Name - actually the partial name - of the generated resource.
|
||||
// The full name ends up being something like
|
||||
// NamePrefix + this.Name + hash(content of generated resource).
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Behavior of generated resource, must be one of:
|
||||
// 'create': create a new one
|
||||
// 'replace': replace the existing one
|
||||
// 'merge': merge with the existing one
|
||||
Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"`
|
||||
|
||||
// KvPairSources for the generator.
|
||||
KvPairSources `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Local overrides to global generatorOptions field.
|
||||
Options *GeneratorOptions `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
}
|
||||
70
vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go
generated
vendored
Normal file
70
vendor/sigs.k8s.io/kustomize/api/types/generatoroptions.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
type GeneratorOptions struct {
|
||||
// Labels to add to all generated resources.
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// Annotations to add to all generated resources.
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
|
||||
// DisableNameSuffixHash if true disables the default behavior of adding a
|
||||
// suffix to the names of generated resources that is a hash of the
|
||||
// resource contents.
|
||||
DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"`
|
||||
}
|
||||
|
||||
// MergeGlobalOptionsIntoLocal merges two instances of GeneratorOptions.
|
||||
// Values in the first 'local' argument cannot be overridden by the second
|
||||
// 'global' argument, except in the case of booleans.
|
||||
//
|
||||
// With booleans, there's no way to distinguish an 'intentional'
|
||||
// false from 'default' false. So the rule is, if the global value
|
||||
// of the value of a boolean is true, i.e. disable, it trumps the
|
||||
// local value. If the global value is false, then the local value is
|
||||
// respected. Bottom line: a local false cannot override a global true.
|
||||
//
|
||||
// boolean fields are always a bad idea; should always use enums instead.
|
||||
func MergeGlobalOptionsIntoLocal(
|
||||
localOpts *GeneratorOptions,
|
||||
globalOpts *GeneratorOptions) *GeneratorOptions {
|
||||
if globalOpts == nil {
|
||||
return localOpts
|
||||
}
|
||||
if localOpts == nil {
|
||||
localOpts = &GeneratorOptions{}
|
||||
}
|
||||
overrideMap(&localOpts.Labels, globalOpts.Labels)
|
||||
overrideMap(&localOpts.Annotations, globalOpts.Annotations)
|
||||
if globalOpts.DisableNameSuffixHash {
|
||||
localOpts.DisableNameSuffixHash = true
|
||||
}
|
||||
return localOpts
|
||||
}
|
||||
|
||||
func overrideMap(localMap *map[string]string, globalMap map[string]string) {
|
||||
if *localMap == nil {
|
||||
if globalMap != nil {
|
||||
*localMap = CopyMap(globalMap)
|
||||
}
|
||||
return
|
||||
}
|
||||
for k, v := range globalMap {
|
||||
_, ok := (*localMap)[k]
|
||||
if !ok {
|
||||
(*localMap)[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CopyMap copies a map.
|
||||
func CopyMap(in map[string]string) map[string]string {
|
||||
out := make(map[string]string)
|
||||
for k, v := range in {
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
114
vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go
generated
vendored
Normal file
114
vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type HelmGlobals struct {
|
||||
// ChartHome is a file path, relative to the kustomization root,
|
||||
// to a directory containing a subdirectory for each chart to be
|
||||
// included in the kustomization.
|
||||
// The default value of this field is "charts".
|
||||
// So, for example, kustomize looks for the minecraft chart
|
||||
// at {kustomizationRoot}/{ChartHome}/minecraft.
|
||||
// If the chart is there at build time, kustomize will use it as found,
|
||||
// and not check version numbers or dates.
|
||||
// If the chart is not there, kustomize will attempt to pull it
|
||||
// using the version number specified in the kustomization file,
|
||||
// and put it there. To suppress the pull attempt, simply assure
|
||||
// that the chart is already there.
|
||||
ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"`
|
||||
|
||||
// ConfigHome defines a value that kustomize should pass to helm via
|
||||
// the HELM_CONFIG_HOME environment variable. kustomize doesn't attempt
|
||||
// to read or write this directory.
|
||||
// If omitted, {tmpDir}/helm is used, where {tmpDir} is some temporary
|
||||
// directory created by kustomize for the benefit of helm.
|
||||
// Likewise, kustomize sets
|
||||
// HELM_CACHE_HOME={ConfigHome}/.cache
|
||||
// HELM_DATA_HOME={ConfigHome}/.data
|
||||
// for the helm subprocess.
|
||||
ConfigHome string `json:"configHome,omitempty" yaml:"configHome,omitempty"`
|
||||
}
|
||||
|
||||
type HelmChart struct {
|
||||
// Name is the name of the chart, e.g. 'minecraft'.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// Version is the version of the chart, e.g. '3.1.3'
|
||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||
|
||||
// Repo is a URL locating the chart on the internet.
|
||||
// This is the argument to helm's `--repo` flag, e.g.
|
||||
// `https://itzg.github.io/minecraft-server-charts`.
|
||||
Repo string `json:"repo,omitempty" yaml:"repo,omitempty"`
|
||||
|
||||
// ReleaseName replaces RELEASE-NAME in chart template output,
|
||||
// making a particular inflation of a chart unique with respect to
|
||||
// other inflations of the same chart in a cluster. It's the first
|
||||
// argument to the helm `install` and `template` commands, i.e.
|
||||
// helm install {RELEASE-NAME} {chartName}
|
||||
// helm template {RELEASE-NAME} {chartName}
|
||||
// If omitted, the flag --generate-name is passed to 'helm template'.
|
||||
ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"`
|
||||
|
||||
// ValuesFile is local file path to a values file to use _instead of_
|
||||
// the default values that accompanied the chart.
|
||||
// The default values are in '{ChartHome}/{Name}/values.yaml'.
|
||||
ValuesFile string `json:"valuesFile,omitempty" yaml:"valuesFile,omitempty"`
|
||||
|
||||
// ValuesInline holds value mappings specified directly,
|
||||
// rather than in a separate file.
|
||||
ValuesInline map[string]interface{} `json:"valuesInline,omitempty" yaml:"valuesInline,omitempty"`
|
||||
|
||||
// ValuesMerge specifies how to treat ValuesInline with respect to Values.
|
||||
// Legal values: 'merge', 'override', 'replace'.
|
||||
// Defaults to 'override'.
|
||||
ValuesMerge string `json:"valuesMerge,omitempty" yaml:"valuesMerge,omitempty"`
|
||||
}
|
||||
|
||||
// HelmChartArgs contains arguments to helm.
|
||||
// Deprecated. Use HelmGlobals and HelmChart instead.
|
||||
type HelmChartArgs struct {
|
||||
ChartName string `json:"chartName,omitempty" yaml:"chartName,omitempty"`
|
||||
ChartVersion string `json:"chartVersion,omitempty" yaml:"chartVersion,omitempty"`
|
||||
ChartRepoURL string `json:"chartRepoUrl,omitempty" yaml:"chartRepoUrl,omitempty"`
|
||||
ChartHome string `json:"chartHome,omitempty" yaml:"chartHome,omitempty"`
|
||||
ChartRepoName string `json:"chartRepoName,omitempty" yaml:"chartRepoName,omitempty"`
|
||||
HelmBin string `json:"helmBin,omitempty" yaml:"helmBin,omitempty"`
|
||||
HelmHome string `json:"helmHome,omitempty" yaml:"helmHome,omitempty"`
|
||||
Values string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
ValuesLocal map[string]interface{} `json:"valuesLocal,omitempty" yaml:"valuesLocal,omitempty"`
|
||||
ValuesMerge string `json:"valuesMerge,omitempty" yaml:"valuesMerge,omitempty"`
|
||||
ReleaseName string `json:"releaseName,omitempty" yaml:"releaseName,omitempty"`
|
||||
ReleaseNamespace string `json:"releaseNamespace,omitempty" yaml:"releaseNamespace,omitempty"`
|
||||
ExtraArgs []string `json:"extraArgs,omitempty" yaml:"extraArgs,omitempty"`
|
||||
}
|
||||
|
||||
// SplitHelmParameters splits helm parameters into
|
||||
// per-chart params and global chart-independent parameters.
|
||||
func SplitHelmParameters(
|
||||
oldArgs []HelmChartArgs) (charts []HelmChart, globals HelmGlobals) {
|
||||
for _, old := range oldArgs {
|
||||
charts = append(charts, makeHelmChartFromHca(&old))
|
||||
if old.HelmHome != "" {
|
||||
// last non-empty wins
|
||||
globals.ConfigHome = old.HelmHome
|
||||
}
|
||||
if old.ChartHome != "" {
|
||||
// last non-empty wins
|
||||
globals.ChartHome = old.ChartHome
|
||||
}
|
||||
}
|
||||
return charts, globals
|
||||
}
|
||||
|
||||
func makeHelmChartFromHca(old *HelmChartArgs) (c HelmChart) {
|
||||
c.Name = old.ChartName
|
||||
c.Version = old.ChartVersion
|
||||
c.Repo = old.ChartRepoURL
|
||||
c.ValuesFile = old.Values
|
||||
c.ValuesInline = old.ValuesLocal
|
||||
c.ValuesMerge = old.ValuesMerge
|
||||
c.ReleaseName = old.ReleaseName
|
||||
return
|
||||
}
|
||||
21
vendor/sigs.k8s.io/kustomize/api/types/image.go
generated
vendored
Normal file
21
vendor/sigs.k8s.io/kustomize/api/types/image.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Image contains an image name, a new name, a new tag or digest,
|
||||
// which will replace the original name and tag.
|
||||
type Image struct {
|
||||
// Name is a tag-less image name.
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// NewName is the value used to replace the original name.
|
||||
NewName string `json:"newName,omitempty" yaml:"newName,omitempty"`
|
||||
|
||||
// NewTag is the value used to replace the original tag.
|
||||
NewTag string `json:"newTag,omitempty" yaml:"newTag,omitempty"`
|
||||
|
||||
// Digest is the value used to replace the original image tag.
|
||||
// If digest is present NewTag value is ignored.
|
||||
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
|
||||
}
|
||||
16
vendor/sigs.k8s.io/kustomize/api/types/inventory.go
generated
vendored
Normal file
16
vendor/sigs.k8s.io/kustomize/api/types/inventory.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Inventory records all objects touched in a build operation.
|
||||
type Inventory struct {
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
ConfigMap NameArgs `json:"configMap,omitempty" yaml:"configMap,omitempty"`
|
||||
}
|
||||
|
||||
// NameArgs holds both namespace and name.
|
||||
type NameArgs struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
261
vendor/sigs.k8s.io/kustomize/api/types/kustomization.go
generated
vendored
Normal file
261
vendor/sigs.k8s.io/kustomize/api/types/kustomization.go
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
KustomizationVersion = "kustomize.config.k8s.io/v1beta1"
|
||||
KustomizationKind = "Kustomization"
|
||||
ComponentVersion = "kustomize.config.k8s.io/v1alpha1"
|
||||
ComponentKind = "Component"
|
||||
MetadataNamespacePath = "metadata/namespace"
|
||||
)
|
||||
|
||||
// Kustomization holds the information needed to generate customized k8s api resources.
|
||||
type Kustomization struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
|
||||
// MetaData is a pointer to avoid marshalling empty struct
|
||||
MetaData *ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
// OpenAPI contains information about what kubernetes schema to use.
|
||||
OpenAPI map[string]string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
|
||||
|
||||
//
|
||||
// Operators - what kustomize can do.
|
||||
//
|
||||
|
||||
// NamePrefix will prefix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
|
||||
// NameSuffix will suffix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
|
||||
|
||||
// Namespace to add to all objects.
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
||||
// CommonLabels to add to all objects and selectors.
|
||||
CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
|
||||
|
||||
// Labels to add to all objects but not selectors.
|
||||
Labels []Label `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
|
||||
// CommonAnnotations to add to all objects.
|
||||
CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
|
||||
// PatchesStrategicMerge specifies the relative path to a file
|
||||
// containing a strategic merge patch. Format documented at
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md
|
||||
// URLs and globs are not supported.
|
||||
PatchesStrategicMerge []PatchStrategicMerge `json:"patchesStrategicMerge,omitempty" yaml:"patchesStrategicMerge,omitempty"`
|
||||
|
||||
// JSONPatches is a list of JSONPatch for applying JSON patch.
|
||||
// Format documented at https://tools.ietf.org/html/rfc6902
|
||||
// and http://jsonpatch.com
|
||||
PatchesJson6902 []Patch `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"`
|
||||
|
||||
// Patches is a list of patches, where each one can be either a
|
||||
// Strategic Merge Patch or a JSON patch.
|
||||
// Each patch can be applied to multiple target objects.
|
||||
Patches []Patch `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
|
||||
// Images is a list of (image name, new name, new tag or digest)
|
||||
// for changing image names, tags or digests. This can also be achieved with a
|
||||
// patch, but this operator is simpler to specify.
|
||||
Images []Image `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
|
||||
// Replicas is a list of {resourcename, count} that allows for simpler replica
|
||||
// specification. This can also be done with a patch.
|
||||
Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
|
||||
// Vars allow things modified by kustomize to be injected into a
|
||||
// kubernetes object specification. A var is a name (e.g. FOO) associated
|
||||
// with a field in a specific resource instance. The field must
|
||||
// contain a value of type string/bool/int/float, and defaults to the name field
|
||||
// of the instance. Any appearance of "$(FOO)" in the object
|
||||
// spec will be replaced at kustomize build time, after the final
|
||||
// value of the specified field has been determined.
|
||||
Vars []Var `json:"vars,omitempty" yaml:"vars,omitempty"`
|
||||
|
||||
//
|
||||
// Operands - what kustomize operates on.
|
||||
//
|
||||
|
||||
// Resources specifies relative paths to files holding YAML representations
|
||||
// of kubernetes API objects, or specifications of other kustomizations
|
||||
// via relative paths, absolute paths, or URLs.
|
||||
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
|
||||
// Components specifies relative paths to specifications of other Components
|
||||
// via relative paths, absolute paths, or URLs.
|
||||
Components []string `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
|
||||
// Crds specifies relative paths to Custom Resource Definition files.
|
||||
// This allows custom resources to be recognized as operands, making
|
||||
// it possible to add them to the Resources list.
|
||||
// CRDs themselves are not modified.
|
||||
Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"`
|
||||
|
||||
// Deprecated.
|
||||
// Anything that would have been specified here should
|
||||
// be specified in the Resources field instead.
|
||||
Bases []string `json:"bases,omitempty" yaml:"bases,omitempty"`
|
||||
|
||||
//
|
||||
// Generators (operators that create operands)
|
||||
//
|
||||
|
||||
// ConfigMapGenerator is a list of configmaps to generate from
|
||||
// local data (one configMap per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
ConfigMapGenerator []ConfigMapArgs `json:"configMapGenerator,omitempty" yaml:"configMapGenerator,omitempty"`
|
||||
|
||||
// SecretGenerator is a list of secrets to generate from
|
||||
// local data (one secret per list item).
|
||||
// The resulting resource is a normal operand, subject to
|
||||
// name prefixing, patching, etc. By default, the name of
|
||||
// the map will have a suffix hash generated from its contents.
|
||||
SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"`
|
||||
|
||||
// HelmGlobals contains helm configuration that isn't chart specific.
|
||||
HelmGlobals *HelmGlobals `json:"helmGlobals,omitempty" yaml:"helmGlobals,omitempty"`
|
||||
|
||||
// HelmCharts is a list of helm chart configuration instances.
|
||||
HelmCharts []HelmChart `json:"helmCharts,omitempty" yaml:"helmCharts,omitempty"`
|
||||
|
||||
// HelmChartInflationGenerator is a list of helm chart configurations.
|
||||
// Deprecated. Auto-converted to HelmGlobals and HelmCharts.
|
||||
HelmChartInflationGenerator []HelmChartArgs `json:"helmChartInflationGenerator,omitempty" yaml:"helmChartInflationGenerator,omitempty"`
|
||||
|
||||
// GeneratorOptions modify behavior of all ConfigMap and Secret generators.
|
||||
GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"`
|
||||
|
||||
// Configurations is a list of transformer configuration files
|
||||
Configurations []string `json:"configurations,omitempty" yaml:"configurations,omitempty"`
|
||||
|
||||
// Generators is a list of files containing custom generators
|
||||
Generators []string `json:"generators,omitempty" yaml:"generators,omitempty"`
|
||||
|
||||
// Transformers is a list of files containing transformers
|
||||
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||
|
||||
// Validators is a list of files containing validators
|
||||
Validators []string `json:"validators,omitempty" yaml:"validators,omitempty"`
|
||||
|
||||
// Inventory appends an object that contains the record
|
||||
// of all other objects, which can be used in apply, prune and delete
|
||||
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
|
||||
}
|
||||
|
||||
// FixKustomizationPostUnmarshalling fixes things
|
||||
// like empty fields that should not be empty, or
|
||||
// moving content of deprecated fields to newer
|
||||
// fields.
|
||||
func (k *Kustomization) FixKustomizationPostUnmarshalling() {
|
||||
if k.Kind == "" {
|
||||
k.Kind = KustomizationKind
|
||||
}
|
||||
if k.APIVersion == "" {
|
||||
if k.Kind == ComponentKind {
|
||||
k.APIVersion = ComponentVersion
|
||||
} else {
|
||||
k.APIVersion = KustomizationVersion
|
||||
}
|
||||
}
|
||||
k.Resources = append(k.Resources, k.Bases...)
|
||||
k.Bases = nil
|
||||
for i, g := range k.ConfigMapGenerator {
|
||||
if g.EnvSource != "" {
|
||||
k.ConfigMapGenerator[i].EnvSources =
|
||||
append(g.EnvSources, g.EnvSource)
|
||||
k.ConfigMapGenerator[i].EnvSource = ""
|
||||
}
|
||||
}
|
||||
for i, g := range k.SecretGenerator {
|
||||
if g.EnvSource != "" {
|
||||
k.SecretGenerator[i].EnvSources =
|
||||
append(g.EnvSources, g.EnvSource)
|
||||
k.SecretGenerator[i].EnvSource = ""
|
||||
}
|
||||
}
|
||||
charts, globals := SplitHelmParameters(k.HelmChartInflationGenerator)
|
||||
if k.HelmGlobals == nil {
|
||||
if globals.ChartHome != "" || globals.ConfigHome != "" {
|
||||
k.HelmGlobals = &globals
|
||||
}
|
||||
}
|
||||
k.HelmCharts = append(k.HelmCharts, charts...)
|
||||
// Wipe it for the fix command.
|
||||
k.HelmChartInflationGenerator = nil
|
||||
}
|
||||
|
||||
// FixKustomizationPreMarshalling fixes things
|
||||
// that should occur after the kustomization file
|
||||
// has been processed.
|
||||
func (k *Kustomization) FixKustomizationPreMarshalling() error {
|
||||
// PatchesJson6902 should be under the Patches field.
|
||||
k.Patches = append(k.Patches, k.PatchesJson6902...)
|
||||
k.PatchesJson6902 = nil
|
||||
|
||||
// this fix is not in FixKustomizationPostUnmarshalling because
|
||||
// it will break some commands like `create` and `add`. those
|
||||
// commands depend on 'commonLabels' field
|
||||
if cl := labelFromCommonLabels(k.CommonLabels); cl != nil {
|
||||
// check conflicts between commonLabels and labels
|
||||
for _, l := range k.Labels {
|
||||
for k := range l.Pairs {
|
||||
if _, exist := cl.Pairs[k]; exist {
|
||||
return fmt.Errorf("label name '%s' exists in both commonLabels and labels", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
k.Labels = append(k.Labels, *cl)
|
||||
k.CommonLabels = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *Kustomization) EnforceFields() []string {
|
||||
var errs []string
|
||||
if k.Kind != "" && k.Kind != KustomizationKind && k.Kind != ComponentKind {
|
||||
errs = append(errs, "kind should be "+KustomizationKind+" or "+ComponentKind)
|
||||
}
|
||||
requiredVersion := KustomizationVersion
|
||||
if k.Kind == ComponentKind {
|
||||
requiredVersion = ComponentVersion
|
||||
}
|
||||
if k.APIVersion != "" && k.APIVersion != requiredVersion {
|
||||
errs = append(errs, "apiVersion for "+k.Kind+" should be "+requiredVersion)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// Unmarshal replace k with the content in YAML input y
|
||||
func (k *Kustomization) Unmarshal(y []byte) error {
|
||||
j, err := yaml.YAMLToJSON(y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(j))
|
||||
dec.DisallowUnknownFields()
|
||||
var nk Kustomization
|
||||
err = dec.Decode(&nk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*k = nk
|
||||
return nil
|
||||
}
|
||||
36
vendor/sigs.k8s.io/kustomize/api/types/kvpairsources.go
generated
vendored
Normal file
36
vendor/sigs.k8s.io/kustomize/api/types/kvpairsources.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// KvPairSources defines places to obtain key value pairs.
|
||||
type KvPairSources struct {
|
||||
// LiteralSources is a list of literal
|
||||
// pair sources. Each literal source should
|
||||
// be a key and literal value, e.g. `key=value`
|
||||
LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"`
|
||||
|
||||
// FileSources is a list of file "sources" to
|
||||
// use in creating a list of key, value pairs.
|
||||
// A source takes the form: [{key}=]{path}
|
||||
// If the "key=" part is missing, the key is the
|
||||
// path's basename. If they "key=" part is present,
|
||||
// it becomes the key (replacing the basename).
|
||||
// In either case, the value is the file contents.
|
||||
// Specifying a directory will iterate each named
|
||||
// file in the directory whose basename is a
|
||||
// valid configmap key.
|
||||
FileSources []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
|
||||
// EnvSources is a list of file paths.
|
||||
// The contents of each file should be one
|
||||
// key=value pair per line, e.g. a Docker
|
||||
// or npm ".env" file or a ".ini" file
|
||||
// (wikipedia.org/wiki/INI_file)
|
||||
EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"`
|
||||
|
||||
// Older, singular form of EnvSources.
|
||||
// On edits (e.g. `kustomize fix`) this is merged into the plural form
|
||||
// for consistency with LiteralSources and FileSources.
|
||||
EnvSource string `json:"env,omitempty" yaml:"env,omitempty"`
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/labels.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/labels.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type Label struct {
|
||||
// Pairs contains the key-value pairs for labels to add
|
||||
Pairs map[string]string `json:"pairs,omitempty" yaml:"pairs,omitempty"`
|
||||
// IncludeSelectors inidicates should transformer include the
|
||||
// fieldSpecs for selectors. Custom fieldSpecs specified by
|
||||
// FieldSpecs will be merged with builtin fieldSpecs if this
|
||||
// is true.
|
||||
IncludeSelectors bool `json:"includeSelectors,omitempty" yaml:"includeSelectors,omitempty"`
|
||||
FieldSpecs []FieldSpec `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||
}
|
||||
|
||||
func labelFromCommonLabels(commonLabels map[string]string) *Label {
|
||||
if len(commonLabels) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &Label{
|
||||
Pairs: commonLabels,
|
||||
IncludeSelectors: true,
|
||||
}
|
||||
}
|
||||
24
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions.go
generated
vendored
Normal file
24
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Restrictions on what things can be referred to
|
||||
// in a kustomization file.
|
||||
//
|
||||
//go:generate stringer -type=LoadRestrictions
|
||||
type LoadRestrictions int
|
||||
|
||||
const (
|
||||
LoadRestrictionsUnknown LoadRestrictions = iota
|
||||
|
||||
// Files referenced by a kustomization file must be in
|
||||
// or under the directory holding the kustomization
|
||||
// file itself.
|
||||
LoadRestrictionsRootOnly
|
||||
|
||||
// The kustomization file may specify absolute or
|
||||
// relative paths to patch or resources files outside
|
||||
// its own tree.
|
||||
LoadRestrictionsNone
|
||||
)
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/loadrestrictions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=LoadRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LoadRestrictionsUnknown-0]
|
||||
_ = x[LoadRestrictionsRootOnly-1]
|
||||
_ = x[LoadRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _LoadRestrictions_name = "LoadRestrictionsUnknownLoadRestrictionsRootOnlyLoadRestrictionsNone"
|
||||
|
||||
var _LoadRestrictions_index = [...]uint8{0, 23, 47, 67}
|
||||
|
||||
func (i LoadRestrictions) String() string {
|
||||
if i < 0 || i >= LoadRestrictions(len(_LoadRestrictions_index)-1) {
|
||||
return "LoadRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _LoadRestrictions_name[_LoadRestrictions_index[i]:_LoadRestrictions_index[i+1]]
|
||||
}
|
||||
13
vendor/sigs.k8s.io/kustomize/api/types/objectmeta.go
generated
vendored
Normal file
13
vendor/sigs.k8s.io/kustomize/api/types/objectmeta.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type ObjectMeta struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
|
||||
}
|
||||
10
vendor/sigs.k8s.io/kustomize/api/types/pair.go
generated
vendored
Normal file
10
vendor/sigs.k8s.io/kustomize/api/types/pair.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Pair is a key value pair.
|
||||
type Pair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
34
vendor/sigs.k8s.io/kustomize/api/types/patch.go
generated
vendored
Normal file
34
vendor/sigs.k8s.io/kustomize/api/types/patch.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Patch represent either a Strategic Merge Patch or a JSON patch
|
||||
// and its targets.
|
||||
// The content of the patch can either be from a file
|
||||
// or from an inline string.
|
||||
type Patch struct {
|
||||
// Path is a relative file path to the patch file.
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
|
||||
// Patch is the content of a patch.
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
|
||||
// Target points to the resources that the patch is applied to
|
||||
Target *Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
|
||||
// Options is a list of options for the patch
|
||||
Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
}
|
||||
|
||||
// Equals return true if p equals o.
|
||||
func (p *Patch) Equals(o Patch) bool {
|
||||
targetEqual := (p.Target == o.Target) ||
|
||||
(p.Target != nil && o.Target != nil && *p.Target == *o.Target)
|
||||
return p.Path == o.Path &&
|
||||
p.Patch == o.Patch &&
|
||||
targetEqual &&
|
||||
reflect.DeepEqual(p.Options, o.Options)
|
||||
}
|
||||
9
vendor/sigs.k8s.io/kustomize/api/types/patchstrategicmerge.go
generated
vendored
Normal file
9
vendor/sigs.k8s.io/kustomize/api/types/patchstrategicmerge.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// PatchStrategicMerge represents a relative path to a
|
||||
// stategic merge patch with the format
|
||||
// https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md
|
||||
type PatchStrategicMerge string
|
||||
47
vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go
generated
vendored
Normal file
47
vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
type HelmConfig struct {
|
||||
Enabled bool
|
||||
Command string
|
||||
}
|
||||
|
||||
// PluginConfig holds plugin configuration.
|
||||
type PluginConfig struct {
|
||||
// PluginRestrictions distinguishes plugin restrictions.
|
||||
PluginRestrictions PluginRestrictions
|
||||
|
||||
// BpLoadingOptions distinguishes builtin plugin behaviors.
|
||||
BpLoadingOptions BuiltinPluginLoadingOptions
|
||||
|
||||
// FnpLoadingOptions sets the way function-based plugin behaviors.
|
||||
FnpLoadingOptions FnPluginLoadingOptions
|
||||
|
||||
// HelmConfig contains metadata needed for allowing and running helm.
|
||||
HelmConfig HelmConfig
|
||||
}
|
||||
|
||||
func EnabledPluginConfig(b BuiltinPluginLoadingOptions) (pc *PluginConfig) {
|
||||
pc = MakePluginConfig(PluginRestrictionsNone, b)
|
||||
pc.FnpLoadingOptions.EnableStar = true
|
||||
pc.HelmConfig.Enabled = true
|
||||
// If this command is not on PATH, tests needing it should skip.
|
||||
pc.HelmConfig.Command = "helmV3"
|
||||
return
|
||||
}
|
||||
|
||||
func DisabledPluginConfig() *PluginConfig {
|
||||
return MakePluginConfig(
|
||||
PluginRestrictionsBuiltinsOnly,
|
||||
BploUseStaticallyLinked)
|
||||
}
|
||||
|
||||
func MakePluginConfig(pr PluginRestrictions,
|
||||
b BuiltinPluginLoadingOptions) *PluginConfig {
|
||||
return &PluginConfig{
|
||||
PluginRestrictions: pr,
|
||||
BpLoadingOptions: b,
|
||||
}
|
||||
}
|
||||
58
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go
generated
vendored
Normal file
58
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Some plugin classes
|
||||
// - builtin: plugins defined in the kustomize repo.
|
||||
// May be freely used and re-configured.
|
||||
// - local: plugins that aren't builtin but are
|
||||
// locally defined (presumably by the user), meaning
|
||||
// the kustomization refers to them via a relative
|
||||
// file path, not a URL.
|
||||
// - remote: require a build-time download to obtain.
|
||||
// Unadvised, unless one controls the
|
||||
// serving site.
|
||||
//
|
||||
//go:generate stringer -type=PluginRestrictions
|
||||
type PluginRestrictions int
|
||||
|
||||
const (
|
||||
PluginRestrictionsUnknown PluginRestrictions = iota
|
||||
|
||||
// Non-builtin plugins completely disabled.
|
||||
PluginRestrictionsBuiltinsOnly
|
||||
|
||||
// No restrictions, do whatever you want.
|
||||
PluginRestrictionsNone
|
||||
)
|
||||
|
||||
// BuiltinPluginLoadingOptions distinguish ways in which builtin plugins are used.
|
||||
//go:generate stringer -type=BuiltinPluginLoadingOptions
|
||||
type BuiltinPluginLoadingOptions int
|
||||
|
||||
const (
|
||||
BploUndefined BuiltinPluginLoadingOptions = iota
|
||||
|
||||
// Desired in production use for performance.
|
||||
BploUseStaticallyLinked
|
||||
|
||||
// Desired in testing and development cycles where it's undesirable
|
||||
// to generate static code.
|
||||
BploLoadFromFileSys
|
||||
)
|
||||
|
||||
// FnPluginLoadingOptions set way functions-based pluing are restricted
|
||||
type FnPluginLoadingOptions struct {
|
||||
// Allow to run executables
|
||||
EnableExec bool
|
||||
// Allow to run starlark
|
||||
EnableStar bool
|
||||
// Allow container access to network
|
||||
Network bool
|
||||
NetworkName string
|
||||
// list of mounts
|
||||
Mounts []string
|
||||
// list of env variables to pass to fn
|
||||
Env []string
|
||||
}
|
||||
25
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions_string.go
generated
vendored
Normal file
25
vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions_string.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Code generated by "stringer -type=PluginRestrictions"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[PluginRestrictionsUnknown-0]
|
||||
_ = x[PluginRestrictionsBuiltinsOnly-1]
|
||||
_ = x[PluginRestrictionsNone-2]
|
||||
}
|
||||
|
||||
const _PluginRestrictions_name = "PluginRestrictionsUnknownPluginRestrictionsBuiltinsOnlyPluginRestrictionsNone"
|
||||
|
||||
var _PluginRestrictions_index = [...]uint8{0, 25, 55, 77}
|
||||
|
||||
func (i PluginRestrictions) String() string {
|
||||
if i < 0 || i >= PluginRestrictions(len(_PluginRestrictions_index)-1) {
|
||||
return "PluginRestrictions(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _PluginRestrictions_name[_PluginRestrictions_index[i]:_PluginRestrictions_index[i+1]]
|
||||
}
|
||||
59
vendor/sigs.k8s.io/kustomize/api/types/replacement.go
generated
vendored
Normal file
59
vendor/sigs.k8s.io/kustomize/api/types/replacement.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
const DefaultReplacementFieldPath = "metadata.name"
|
||||
|
||||
// Replacement defines how to perform a substitution
|
||||
// where it is from and where it is to.
|
||||
type Replacement struct {
|
||||
// The source of the value.
|
||||
Source *SourceSelector `json:"source" yaml:"source"`
|
||||
|
||||
// The N fields to write the value to.
|
||||
Targets []*TargetSelector `json:"targets" yaml:"targets"`
|
||||
}
|
||||
|
||||
// SourceSelector is the source of the replacement transformer.
|
||||
type SourceSelector struct {
|
||||
// A specific object to read it from.
|
||||
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Structured field path expected in the allowed object.
|
||||
FieldPath string `json:"fieldPath" yaml:"fieldPath"`
|
||||
|
||||
// Used to refine the interpretation of the field.
|
||||
Options *FieldOptions `json:"options" yaml:"options"`
|
||||
}
|
||||
|
||||
// TargetSelector specifies fields in one or more objects.
|
||||
type TargetSelector struct {
|
||||
// Include objects that match this.
|
||||
Select *Selector `json:"select" yaml:"select"`
|
||||
|
||||
// From the allowed set, remove objects that match this.
|
||||
Reject []*Selector `json:"reject" yaml:"reject"`
|
||||
|
||||
// Structured field paths expected in each allowed object.
|
||||
FieldPaths []string `json:"fieldPaths" yaml:"fieldPaths"`
|
||||
|
||||
// Used to refine the interpretation of the field.
|
||||
Options *FieldOptions `json:"options" yaml:"options"`
|
||||
}
|
||||
|
||||
// FieldOptions refine the interpretation of FieldPaths.
|
||||
type FieldOptions struct {
|
||||
// Used to split/join the field.
|
||||
Delimiter string `json:"delimiter" yaml:"delimiter"`
|
||||
|
||||
// Which position in the split to consider.
|
||||
Index int `json:"index" yaml:"index"`
|
||||
|
||||
// TODO (#3492): Implement use of this option
|
||||
// None, Base64, URL, Hex, etc
|
||||
Encoding string `json:"encoding" yaml:"encoding"`
|
||||
|
||||
// If field missing, add it.
|
||||
Create bool `json:"create" yaml:"create"`
|
||||
}
|
||||
16
vendor/sigs.k8s.io/kustomize/api/types/replica.go
generated
vendored
Normal file
16
vendor/sigs.k8s.io/kustomize/api/types/replica.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// Replica specifies a modification to a replica config.
|
||||
// The number of replicas of a resource whose name matches will be set to count.
|
||||
// This struct is used by the ReplicaCountTransform, and is meant to supplement
|
||||
// the existing patch functionality with a simpler syntax for replica configuration.
|
||||
type Replica struct {
|
||||
// The name of the resource to change the replica count
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
|
||||
// The number of replicas required.
|
||||
Count int64 `json:"count" yaml:"count"`
|
||||
}
|
||||
19
vendor/sigs.k8s.io/kustomize/api/types/secretargs.go
generated
vendored
Normal file
19
vendor/sigs.k8s.io/kustomize/api/types/secretargs.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// SecretArgs contains the metadata of how to generate a secret.
|
||||
type SecretArgs struct {
|
||||
// GeneratorArgs for the secret.
|
||||
GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// Type of the secret.
|
||||
//
|
||||
// This is the same field as the secret type field in v1/Secret:
|
||||
// It can be "Opaque" (default), or "kubernetes.io/tls".
|
||||
//
|
||||
// If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two
|
||||
// keys: "tls.key" and "tls.crt"
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
131
vendor/sigs.k8s.io/kustomize/api/types/selector.go
generated
vendored
Normal file
131
vendor/sigs.k8s.io/kustomize/api/types/selector.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// Selector specifies a set of resources.
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type Selector struct {
|
||||
// KrmId refers to a GVKN/Ns of a resource.
|
||||
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// AnnotationSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource annotations.
|
||||
AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"`
|
||||
|
||||
// LabelSelector is a string that follows the label selection expression
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||
// It matches with the resource labels.
|
||||
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
||||
}
|
||||
|
||||
// KrmId refers to a GVKN/Ns of a resource.
|
||||
type KrmId struct {
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// Match returns true if id selects other, i.e. id's fields
|
||||
// either match other's or are empty
|
||||
func (id *KrmId) Match(other *KrmId) bool {
|
||||
return (id.Group == "" || id.Group == other.Group) &&
|
||||
(id.Version == "" || id.Version == other.Version) &&
|
||||
(id.Kind == "" || id.Kind == other.Kind) &&
|
||||
(id.Name == "" || id.Name == other.Name) &&
|
||||
(id.Namespace == "" || id.Namespace == other.Namespace)
|
||||
}
|
||||
|
||||
// SelectorRegex is a Selector with regex in GVK
|
||||
// Any resource that matches intersection of all conditions
|
||||
// is included in this set.
|
||||
type SelectorRegex struct {
|
||||
selector *Selector
|
||||
groupRegex *regexp.Regexp
|
||||
versionRegex *regexp.Regexp
|
||||
kindRegex *regexp.Regexp
|
||||
nameRegex *regexp.Regexp
|
||||
namespaceRegex *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewSelectorRegex returns a pointer to a new SelectorRegex
|
||||
// which uses the same condition as s.
|
||||
func NewSelectorRegex(s *Selector) (*SelectorRegex, error) {
|
||||
sr := new(SelectorRegex)
|
||||
var err error
|
||||
sr.selector = s
|
||||
sr.groupRegex, err = regexp.Compile(anchorRegex(s.Gvk.Group))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.versionRegex, err = regexp.Compile(anchorRegex(s.Gvk.Version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.kindRegex, err = regexp.Compile(anchorRegex(s.Gvk.Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.nameRegex, err = regexp.Compile(anchorRegex(s.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.namespaceRegex, err = regexp.Compile(anchorRegex(s.Namespace))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sr, nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^(?:" + pattern + ")$"
|
||||
}
|
||||
|
||||
// MatchGvk return true if gvk can be matched by s.
|
||||
func (s *SelectorRegex) MatchGvk(gvk resid.Gvk) bool {
|
||||
if len(s.selector.Gvk.Group) > 0 {
|
||||
if !s.groupRegex.MatchString(gvk.Group) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Version) > 0 {
|
||||
if !s.versionRegex.MatchString(gvk.Version) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if len(s.selector.Gvk.Kind) > 0 {
|
||||
if !s.kindRegex.MatchString(gvk.Kind) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MatchName returns true if the name in selector is
|
||||
// empty or the n can be matches by the name in selector
|
||||
func (s *SelectorRegex) MatchName(n string) bool {
|
||||
if s.selector.Name == "" {
|
||||
return true
|
||||
}
|
||||
return s.nameRegex.MatchString(n)
|
||||
}
|
||||
|
||||
// MatchNamespace returns true if the namespace in selector is
|
||||
// empty or the ns can be matches by the namespace in selector
|
||||
func (s *SelectorRegex) MatchNamespace(ns string) bool {
|
||||
if s.selector.Namespace == "" {
|
||||
return true
|
||||
}
|
||||
return s.namespaceRegex.MatchString(ns)
|
||||
}
|
||||
11
vendor/sigs.k8s.io/kustomize/api/types/typemeta.go
generated
vendored
Normal file
11
vendor/sigs.k8s.io/kustomize/api/types/typemeta.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
211
vendor/sigs.k8s.io/kustomize/api/types/var.go
generated
vendored
Normal file
211
vendor/sigs.k8s.io/kustomize/api/types/var.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
)
|
||||
|
||||
// Var represents a variable whose value will be sourced
|
||||
// from a field in a Kubernetes object.
|
||||
type Var struct {
|
||||
// Value of identifier name e.g. FOO used in container args, annotations
|
||||
// Appears in pod template as $(FOO)
|
||||
Name string `json:"name" yaml:"name"`
|
||||
|
||||
// ObjRef must refer to a Kubernetes resource under the
|
||||
// purview of this kustomization. ObjRef should use the
|
||||
// raw name of the object (the name specified in its YAML,
|
||||
// before addition of a namePrefix and a nameSuffix).
|
||||
ObjRef Target `json:"objref" yaml:"objref"`
|
||||
|
||||
// FieldRef refers to the field of the object referred to by
|
||||
// ObjRef whose value will be extracted for use in
|
||||
// replacing $(FOO).
|
||||
// If unspecified, this defaults to fieldPath: $defaultFieldPath
|
||||
FieldRef FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
|
||||
}
|
||||
|
||||
// Target refers to a kubernetes object by Group, Version, Kind and Name
|
||||
// gvk.Gvk contains Group, Version and Kind
|
||||
// APIVersion is added to keep the backward compatibility of using ObjectReference
|
||||
// for Var.ObjRef
|
||||
type Target struct {
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// GVK returns the Gvk object in Target
|
||||
func (t *Target) GVK() resid.Gvk {
|
||||
if t.APIVersion == "" {
|
||||
return t.Gvk
|
||||
}
|
||||
versions := strings.Split(t.APIVersion, "/")
|
||||
if len(versions) == 2 {
|
||||
t.Group = versions[0]
|
||||
t.Version = versions[1]
|
||||
}
|
||||
if len(versions) == 1 {
|
||||
t.Version = versions[0]
|
||||
}
|
||||
return t.Gvk
|
||||
}
|
||||
|
||||
// FieldSelector contains the fieldPath to an object field.
|
||||
// This struct is added to keep the backward compatibility of using ObjectFieldSelector
|
||||
// for Var.FieldRef
|
||||
type FieldSelector struct {
|
||||
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
||||
}
|
||||
|
||||
// defaulting sets reference to field used by default.
|
||||
func (v *Var) Defaulting() {
|
||||
if v.FieldRef.FieldPath == "" {
|
||||
v.FieldRef.FieldPath = DefaultReplacementFieldPath
|
||||
}
|
||||
v.ObjRef.GVK()
|
||||
}
|
||||
|
||||
// DeepEqual returns true if var a and b are Equals.
|
||||
// Note 1: The objects are unchanged by the VarEqual
|
||||
// Note 2: Should be normalize be FieldPath before doing
|
||||
// the DeepEqual. spec.a[b] is supposed to be the same
|
||||
// as spec.a.b
|
||||
func (v Var) DeepEqual(other Var) bool {
|
||||
v.Defaulting()
|
||||
other.Defaulting()
|
||||
return reflect.DeepEqual(v, other)
|
||||
}
|
||||
|
||||
// VarSet is a set of Vars where no var.Name is repeated.
|
||||
type VarSet struct {
|
||||
set map[string]Var
|
||||
}
|
||||
|
||||
// NewVarSet returns an initialized VarSet
|
||||
func NewVarSet() VarSet {
|
||||
return VarSet{set: map[string]Var{}}
|
||||
}
|
||||
|
||||
// AsSlice returns the vars as a slice.
|
||||
func (vs *VarSet) AsSlice() []Var {
|
||||
s := make([]Var, len(vs.set))
|
||||
i := 0
|
||||
for _, v := range vs.set {
|
||||
s[i] = v
|
||||
i++
|
||||
}
|
||||
sort.Sort(byName(s))
|
||||
return s
|
||||
}
|
||||
|
||||
// Copy returns a copy of the var set.
|
||||
func (vs *VarSet) Copy() VarSet {
|
||||
newSet := make(map[string]Var, len(vs.set))
|
||||
for k, v := range vs.set {
|
||||
newSet[k] = v
|
||||
}
|
||||
return VarSet{set: newSet}
|
||||
}
|
||||
|
||||
// MergeSet absorbs other vars with error on name collision.
|
||||
func (vs *VarSet) MergeSet(incoming VarSet) error {
|
||||
for _, incomingVar := range incoming.set {
|
||||
if err := vs.Merge(incomingVar); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeSlice absorbs a Var slice with error on name collision.
|
||||
// Empty fields in incoming vars are defaulted.
|
||||
func (vs *VarSet) MergeSlice(incoming []Var) error {
|
||||
for _, v := range incoming {
|
||||
if err := vs.Merge(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Merge absorbs another Var with error on name collision.
|
||||
// Empty fields in incoming Var is defaulted.
|
||||
func (vs *VarSet) Merge(v Var) error {
|
||||
if vs.Contains(v) {
|
||||
return fmt.Errorf(
|
||||
"var '%s' already encountered", v.Name)
|
||||
}
|
||||
v.Defaulting()
|
||||
vs.set[v.Name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbSet absorbs other vars with error on (name,value) collision.
|
||||
func (vs *VarSet) AbsorbSet(incoming VarSet) error {
|
||||
for _, v := range incoming.set {
|
||||
if err := vs.Absorb(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbSlice absorbs a Var slice with error on (name,value) collision.
|
||||
// Empty fields in incoming vars are defaulted.
|
||||
func (vs *VarSet) AbsorbSlice(incoming []Var) error {
|
||||
for _, v := range incoming {
|
||||
if err := vs.Absorb(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Absorb absorbs another Var with error on (name,value) collision.
|
||||
// Empty fields in incoming Var is defaulted.
|
||||
func (vs *VarSet) Absorb(v Var) error {
|
||||
conflicting := vs.Get(v.Name)
|
||||
if conflicting == nil {
|
||||
// no conflict. The var is valid.
|
||||
v.Defaulting()
|
||||
vs.set[v.Name] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(v, *conflicting) {
|
||||
// two vars with the same name are pointing at two
|
||||
// different resources.
|
||||
return fmt.Errorf(
|
||||
"var '%s' already encountered", v.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains is true if the set has the other var.
|
||||
func (vs *VarSet) Contains(other Var) bool {
|
||||
return vs.Get(other.Name) != nil
|
||||
}
|
||||
|
||||
// Get returns the var with the given name, else nil.
|
||||
func (vs *VarSet) Get(name string) *Var {
|
||||
if v, found := vs.set[name]; found {
|
||||
return &v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// byName is a sort interface which sorts Vars by name alphabetically
|
||||
type byName []Var
|
||||
|
||||
func (v byName) Len() int { return len(v) }
|
||||
func (v byName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
||||
func (v byName) Less(i, j int) bool { return v[i].Name < v[j].Name }
|
||||
201
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE
generated
vendored
Normal file
201
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
2
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE_TEMPLATE
generated
vendored
Normal file
2
vendor/sigs.k8s.io/kustomize/kyaml/LICENSE_TEMPLATE
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Copyright {{.Year}} {{.Holder}}
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
40
vendor/sigs.k8s.io/kustomize/kyaml/errors/errors.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/kyaml/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package errors provides libraries for working with the go-errors/errors library.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
goerrors "github.com/go-errors/errors"
|
||||
)
|
||||
|
||||
// Wrap returns err wrapped in a go-error. If err is nil, returns nil.
|
||||
func Wrap(err interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return goerrors.Wrap(err, 1)
|
||||
}
|
||||
|
||||
// WrapPrefixf returns err wrapped in a go-error with a message prefix. If err is nil, returns nil.
|
||||
func WrapPrefixf(err interface{}, msg string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return goerrors.WrapPrefix(err, fmt.Sprintf(msg, args...), 1)
|
||||
}
|
||||
|
||||
// Errorf returns a new go-error.
|
||||
func Errorf(msg string, args ...interface{}) error {
|
||||
return goerrors.Wrap(fmt.Errorf(msg, args...), 1)
|
||||
}
|
||||
|
||||
// GetStack returns a stack trace for the error if it has one
|
||||
func GetStack(err error) string {
|
||||
if e, ok := err.(*goerrors.Error); ok {
|
||||
return string(e.Stack())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
61
vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile
generated
vendored
Normal file
61
vendor/sigs.k8s.io/kustomize/kyaml/openapi/Makefile
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2020 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
MYGOBIN = $(shell go env GOBIN)
|
||||
ifeq ($(MYGOBIN),)
|
||||
MYGOBIN = $(shell go env GOPATH)/bin
|
||||
endif
|
||||
API_VERSION := "v1.19.1"
|
||||
|
||||
.PHONY: all
|
||||
all: \
|
||||
kustomizationapi/swagger.go \
|
||||
kubernetesapi/swagger.go \
|
||||
kubernetesapi/openapiinfo.go
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm kustomizationapi/swagger.go
|
||||
rm kubernetesapi/openapiinfo.go
|
||||
|
||||
# This will remove all currently built-in schema,
|
||||
# so think twice before deleting.
|
||||
# To replace what this will delete typically requires the ability
|
||||
# to contact a live kubernetes API server.
|
||||
.PHONY: nuke
|
||||
nuke: clean
|
||||
rm -r kubernetesapi/*
|
||||
|
||||
$(MYGOBIN)/go-bindata:
|
||||
go install github.com/go-bindata/go-bindata/v3/go-bindata
|
||||
|
||||
$(MYGOBIN)/kind:
|
||||
( \
|
||||
set -e; \
|
||||
d=$(shell mktemp -d); cd $$d; \
|
||||
wget -O ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(shell uname)-amd64; \
|
||||
chmod +x ./kind; \
|
||||
mv ./kind $(MYGOBIN); \
|
||||
rm -rf $$d; \
|
||||
)
|
||||
|
||||
$(MYGOBIN)/kpt:
|
||||
../../hack/install_kpt.sh 0.34.0 $(MYGOBIN)
|
||||
|
||||
kustomizationapi/swagger.go: $(MYGOBIN)/go-bindata kustomizationapi/swagger.json
|
||||
$(MYGOBIN)/go-bindata \
|
||||
--pkg kustomizationapi \
|
||||
-o kustomizationapi/swagger.go \
|
||||
kustomizationapi/swagger.json
|
||||
|
||||
.PHONY: kubernetesapi/openapiinfo.go
|
||||
kubernetesapi/openapiinfo.go:
|
||||
./scripts/makeOpenApiInfoDotGo.sh
|
||||
|
||||
.PHONY: kubernetesapi/swagger.json
|
||||
kubernetesapi/swagger.json: $(MYGOBIN)/kind $(MYGOBIN)/kpt
|
||||
./scripts/fetchSchemaFromCluster.sh $(API_VERSION)
|
||||
|
||||
.PHONY: kubernetesapi/swagger.go
|
||||
kubernetesapi/swagger.go: $(MYGOBIN)/go-bindata kubernetesapi/swagger.json
|
||||
./scripts/generateSwaggerDotGo.sh $(API_VERSION)
|
||||
63
vendor/sigs.k8s.io/kustomize/kyaml/openapi/README.md
generated
vendored
Normal file
63
vendor/sigs.k8s.io/kustomize/kyaml/openapi/README.md
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# Sampling New OpenAPI Data
|
||||
|
||||
[OpenAPI schema]: ./kubernetesapi/
|
||||
[kind]: https://hub.docker.com/r/kindest/node/tags
|
||||
|
||||
This document describes how to fetch OpenAPI data from a
|
||||
live kubernetes API server, e.g. an instance of [kind].
|
||||
|
||||
### Delete all currently built-in schema
|
||||
```
|
||||
make nuke
|
||||
```
|
||||
|
||||
### Add a new built-in schema
|
||||
|
||||
In this directory, fetch the openapi schema and generate the
|
||||
corresponding swagger.go for the kubernetes api:
|
||||
|
||||
```
|
||||
make kubernetesapi/swagger.go
|
||||
```
|
||||
|
||||
To fetch the schema without generating the swagger.go, you can
|
||||
run:
|
||||
|
||||
```
|
||||
make nuke
|
||||
make kubernetesapi/swagger.json
|
||||
```
|
||||
|
||||
Note that generating the swagger.go will re-fetch the schema.
|
||||
|
||||
You can specify a specific version with the "API_VERSION"
|
||||
parameter. The default version is v1.19.1. Here is an
|
||||
example for generating swagger.go for v1.14.1.
|
||||
|
||||
```
|
||||
make kubernetesapi/swagger.go API_VERSION=v1.14.1
|
||||
```
|
||||
|
||||
This will update the [OpenAPI schema]. The above command will
|
||||
create a directory kubernetesapi/v1141 and store the resulting
|
||||
swagger.json and swagger.go files there.
|
||||
|
||||
### Make the schema available for use
|
||||
|
||||
While the above commands generate the swagger.go files, they
|
||||
do not make them available for use nor do they update the
|
||||
info field reported by `kustomize openapi info`. To make the
|
||||
newly fetched schema and swagger.go available:
|
||||
|
||||
```
|
||||
make kubernetesapi/openapiinfo.go
|
||||
```
|
||||
|
||||
### Run all tests
|
||||
|
||||
At the top of the repository, run the tests.
|
||||
|
||||
```
|
||||
make prow-presubmit-check >& /tmp/k.txt; echo $?
|
||||
# The exit code should be zero; if not examine /tmp/k.txt
|
||||
```
|
||||
18
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/openapiinfo.go
generated
vendored
Normal file
18
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/openapiinfo.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by ./scripts/makeOpenApiInfoDotGo.sh; DO NOT EDIT.
|
||||
|
||||
package kubernetesapi
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204"
|
||||
)
|
||||
|
||||
const Info = "{title:Kubernetes,version:v1.20.4}"
|
||||
|
||||
var OpenAPIMustAsset = map[string]func(string) []byte{
|
||||
"v1204": v1204.MustAsset,
|
||||
}
|
||||
|
||||
const DefaultOpenAPI = "v1204"
|
||||
251
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.go
generated
vendored
Normal file
251
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
96625
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.json
generated
vendored
Normal file
96625
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1204/swagger.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
249
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go
generated
vendored
Normal file
249
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated for package kustomizationapi by go-bindata DO NOT EDIT. (@generated)
|
||||
// sources:
|
||||
// kustomizationapi/swagger.json
|
||||
package kustomizationapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
// Name return file name
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
// Size return file size
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
|
||||
// Mode return file mode
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
|
||||
// Mode return file modify time
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
|
||||
// IsDir return file whether a directory
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return fi.mode&os.ModeDir != 0
|
||||
}
|
||||
|
||||
// Sys return file is sys mode
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _kustomizationapiSwaggerJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x56\xc1\x6e\xdb\x30\x0c\xbd\xe7\x2b\x04\x6d\xc7\xd8\x45\x6e\x43\x6e\xc3\x0e\x3b\x14\x05\x0a\x74\xb7\xa1\x07\xc6\xa1\x5d\xce\x8e\xa4\x51\xb4\xb1\x6c\xc8\xbf\x0f\xd6\x62\xd7\x4a\xec\x75\x0b\x1a\xac\x4b\x0f\x06\x0c\x99\x7c\x4f\xe4\x7b\x24\xfc\x63\xa6\x94\x5e\x63\x4e\x86\x84\xac\xf1\x7a\xa9\xda\x23\xa5\x34\xd9\xb4\x7c\xe7\x53\x70\x94\x82\x73\x3e\x6d\x16\xe9\x07\x6b\x72\x2a\x6e\xc0\xbd\xe7\xe2\x31\x52\x29\xed\xd8\x3a\x64\x21\x1c\x9e\x2a\xa5\x3f\xa2\x41\x06\xb1\x7c\x90\x10\x3e\xbe\x65\xcc\xf5\x52\xe9\x37\x57\x03\xfe\xab\x11\xda\x18\xa5\x87\xd8\xed\xdf\x76\xf3\xee\x1a\xb0\x5e\x07\x14\xa8\x6e\x87\x17\xca\xa1\xf2\xd8\x07\xc9\xd6\x61\x4b\x6b\x57\x5f\x30\x13\xdd\x9f\x7f\x4b\xca\x7a\x85\x6c\x50\xd0\x27\x05\xdb\xda\x25\x0d\xb2\x27\x6b\x92\x92\xcc\x5a\x2f\xd5\xe7\x9e\x3a\xaa\x23\xc4\xb6\x88\x65\xed\xc5\x6e\xe8\x3b\xa6\x59\x68\x54\x28\x84\x6c\x4f\x11\xa2\xf7\x58\x3a\xee\x65\x14\xb2\xa7\x6d\xa3\x9a\xc5\x0a\x05\x16\xc7\x45\xdf\xcf\x06\xa5\x8f\x69\x75\x87\x19\xa3\xbc\x0c\xa1\x1e\xab\xeb\xba\x1f\xe1\x77\x8a\x78\x61\x32\xc5\xa5\x08\x3c\x10\xe0\xf9\xd5\x9d\xd2\x6b\x52\x60\x03\x1b\xf4\x0e\xb2\x3f\x6f\xfe\x3c\x4e\x3e\x25\x6f\x85\x0f\xd0\x90\xe5\x53\x72\xaf\x9b\x5b\x20\xbe\xb3\x35\x67\x78\xba\x23\x63\x94\x0b\x71\x56\x2c\xfe\xf3\x9b\xeb\x7a\x7f\x19\x90\x5f\x50\xbd\xb9\x18\xbf\xd6\xc4\x18\x17\xa4\x3f\x6d\x1d\xde\xa0\x40\xc7\x74\x3f\x7f\xca\x8c\x59\xb7\xfb\xfa\x4a\x0e\x05\x26\xc1\xcd\xa1\xea\x7f\xa3\x7b\xbc\x5d\x07\x20\xbb\xf9\x98\x11\x81\x19\xb6\x71\x27\x23\x4d\x1d\x48\xf6\x90\x6c\x90\x0b\x4c\x4a\xdc\xb6\x29\x61\x26\x9e\xca\xf0\xc2\x20\x58\x84\x84\x90\x3d\xee\x75\x1f\x56\xc5\xd9\x9a\x31\xd8\x44\x2f\xb2\x13\xff\xf5\x30\xc6\xc3\x72\x86\x61\x9c\xd8\x83\x93\xc3\x55\x91\x20\x43\x75\xb4\x33\x27\x5c\x34\xb5\x8b\x7f\x6f\x90\x51\x1b\xe7\x54\x1d\xaf\xea\xf3\xd3\xa2\x69\xfe\x0d\xeb\xeb\xf8\x8f\x89\x0d\x78\xaa\xc1\x67\xed\xb3\xfb\x19\x00\x00\xff\xff\x2f\x39\x79\xd0\x6e\x0c\x00\x00")
|
||||
|
||||
func kustomizationapiSwaggerJsonBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_kustomizationapiSwaggerJson,
|
||||
"kustomizationapi/swagger.json",
|
||||
)
|
||||
}
|
||||
|
||||
func kustomizationapiSwaggerJson() (*asset, error) {
|
||||
bytes, err := kustomizationapiSwaggerJsonBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "kustomizationapi/swagger.json", size: 3182, mode: os.FileMode(420), modTime: time.Unix(1615228558, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"kustomizationapi/swagger.json": kustomizationapiSwaggerJson,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"kustomizationapi": &bintree{nil, map[string]*bintree{
|
||||
"swagger.json": &bintree{kustomizationapiSwaggerJson, map[string]*bintree{}},
|
||||
}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
130
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.json
generated
vendored
Normal file
130
vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.json
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"definitions": {
|
||||
"io.k8s.api.apps.v1.ConfigMapArgs": {
|
||||
"properties": {
|
||||
"GeneratorArgs": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.GeneratorArgs"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "ConfigMapArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.SecretArgs": {
|
||||
"properties": {
|
||||
"GeneratorArgs": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.GeneratorArgs"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "SecretArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.GeneratorArgs": {
|
||||
"properties": {
|
||||
"namespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"behavior": {
|
||||
"type": "string"
|
||||
},
|
||||
"KvPairSources": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.KvPairSources"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "GeneratorArgs",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.Kustomization": {
|
||||
"required": [
|
||||
"TypeMeta"
|
||||
],
|
||||
"properties": {
|
||||
"configMapGenerator": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.ConfigMapArgs"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-patch-merge-key": "name",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
},
|
||||
"secretGenerator": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.apps.v1.SecretArgs"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-patch-merge-key": "name",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "Kustomization",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.api.apps.v1.KvPairSources": {
|
||||
"properties": {
|
||||
"literals": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"files": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"envs": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"env": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "kustomize.config.k8s.io",
|
||||
"kind": "KvPairSources",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
607
vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go
generated
vendored
Normal file
607
vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go
generated
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package openapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// globalSchema contains global state information about the openapi
|
||||
var globalSchema openapiData
|
||||
|
||||
// kubernetesOpenAPIVersion specifies which builtin kubernetes schema to use
|
||||
var kubernetesOpenAPIVersion string
|
||||
|
||||
// customSchemaFile stores the custom OpenApi schema if it is provided
|
||||
var customSchema []byte
|
||||
|
||||
// openapiData contains the parsed openapi state. this is in a struct rather than
|
||||
// a list of vars so that it can be reset from tests.
|
||||
type openapiData struct {
|
||||
// schema holds the OpenAPI schema data
|
||||
schema spec.Schema
|
||||
|
||||
// schemaForResourceType is a map of Resource types to their schemas
|
||||
schemaByResourceType map[yaml.TypeMeta]*spec.Schema
|
||||
|
||||
// namespaceabilityByResourceType stores whether a given Resource type
|
||||
// is namespaceable or not
|
||||
namespaceabilityByResourceType map[yaml.TypeMeta]bool
|
||||
|
||||
// noUseBuiltInSchema stores whether we want to prevent using the built-n
|
||||
// Kubernetes schema as part of the global schema
|
||||
noUseBuiltInSchema bool
|
||||
|
||||
// schemaInit stores whether or not we've parsed the schema already,
|
||||
// so that we only reparse the when necessary (to speed up performance)
|
||||
schemaInit bool
|
||||
}
|
||||
|
||||
// ResourceSchema wraps the OpenAPI Schema.
|
||||
type ResourceSchema struct {
|
||||
// Schema is the OpenAPI schema for a Resource or field
|
||||
Schema *spec.Schema
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the ResourceSchema is empty
|
||||
func (rs *ResourceSchema) IsMissingOrNull() bool {
|
||||
if rs == nil || rs.Schema == nil {
|
||||
return true
|
||||
}
|
||||
return reflect.DeepEqual(*rs.Schema, spec.Schema{})
|
||||
}
|
||||
|
||||
// SchemaForResourceType returns the Schema for the given Resource
|
||||
// TODO(pwittrock): create a version of this function that will return a schema
|
||||
// which can be used for duck-typed Resources -- e.g. contains common fields such
|
||||
// as metadata, replicas and spec.template.spec
|
||||
func SchemaForResourceType(t yaml.TypeMeta) *ResourceSchema {
|
||||
initSchema()
|
||||
rs, found := globalSchema.schemaByResourceType[t]
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
return &ResourceSchema{Schema: rs}
|
||||
}
|
||||
|
||||
// SupplementaryOpenAPIFieldName is the conventional field name (JSON/YAML) containing
|
||||
// supplementary OpenAPI definitions.
|
||||
const SupplementaryOpenAPIFieldName = "openAPI"
|
||||
|
||||
const Definitions = "definitions"
|
||||
|
||||
// AddSchemaFromFile reads the file at path and parses the OpenAPI definitions
|
||||
// from the field "openAPI", also returns a function to clean the added definitions
|
||||
// The returned clean function is a no-op on error, or else it's a function
|
||||
// that the caller should use to remove the added openAPI definitions from
|
||||
// global schema
|
||||
func SchemaFromFile(path string) (*spec.Schema, error) {
|
||||
object, err := parseOpenAPI(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return schemaUsingField(object, SupplementaryOpenAPIFieldName)
|
||||
}
|
||||
|
||||
// DefinitionRefs returns the list of openAPI definition references present in the
|
||||
// input openAPIPath
|
||||
func DefinitionRefs(openAPIPath string) ([]string, error) {
|
||||
object, err := parseOpenAPI(openAPIPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return definitionRefsFromRNode(object)
|
||||
}
|
||||
|
||||
// definitionRefsFromRNode returns the list of openAPI definitions keys from input
|
||||
// yaml RNode
|
||||
func definitionRefsFromRNode(object *yaml.RNode) ([]string, error) {
|
||||
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, Definitions))
|
||||
if definitions == nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return definitions.Fields()
|
||||
}
|
||||
|
||||
// parseOpenAPI reads openAPIPath yaml and converts it to RNode
|
||||
func parseOpenAPI(openAPIPath string) (*yaml.RNode, error) {
|
||||
b, err := ioutil.ReadFile(openAPIPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
object, err := yaml.Parse(string(b))
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid file %q: %v", openAPIPath, err)
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
// addSchemaUsingField parses the OpenAPI definitions from the specified field.
|
||||
// If field is the empty string, use the whole document as OpenAPI.
|
||||
func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) {
|
||||
if field != "" {
|
||||
// get the field containing the openAPI
|
||||
m := object.Field(field)
|
||||
if m.IsNilOrEmpty() {
|
||||
// doesn't contain openAPI definitions
|
||||
return nil, nil
|
||||
}
|
||||
object = m.Value
|
||||
}
|
||||
|
||||
oAPI, err := object.String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// convert the yaml openAPI to a JSON string by unmarshalling it to an
|
||||
// interface{} and the marshalling it to a string
|
||||
var o interface{}
|
||||
err = yaml.Unmarshal([]byte(oAPI), &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
j, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sc spec.Schema
|
||||
err = sc.UnmarshalJSON(j)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sc, nil
|
||||
}
|
||||
|
||||
// AddSchema parses s, and adds definitions from s to the global schema.
|
||||
func AddSchema(s []byte) error {
|
||||
return parse(s)
|
||||
}
|
||||
|
||||
// ResetOpenAPI resets the openapi data to empty
|
||||
func ResetOpenAPI() {
|
||||
globalSchema = openapiData{}
|
||||
}
|
||||
|
||||
// AddDefinitions adds the definitions to the global schema.
|
||||
func AddDefinitions(definitions spec.Definitions) {
|
||||
// initialize values if they have not yet been set
|
||||
if globalSchema.schemaByResourceType == nil {
|
||||
globalSchema.schemaByResourceType = map[yaml.TypeMeta]*spec.Schema{}
|
||||
}
|
||||
if globalSchema.schema.Definitions == nil {
|
||||
globalSchema.schema.Definitions = spec.Definitions{}
|
||||
}
|
||||
|
||||
// index the schema definitions so we can lookup them up for Resources
|
||||
for k := range definitions {
|
||||
// index by GVK, if no GVK is found then it is the schema for a subfield
|
||||
// of a Resource
|
||||
d := definitions[k]
|
||||
|
||||
// copy definitions to the schema
|
||||
globalSchema.schema.Definitions[k] = d
|
||||
gvk, found := d.VendorExtensible.Extensions[kubernetesGVKExtensionKey]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
// cast the extension to a []map[string]string
|
||||
exts, ok := gvk.([]interface{})
|
||||
if !ok || len(exts) != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
typeMeta, ok := toTypeMeta(exts[0])
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
globalSchema.schemaByResourceType[typeMeta] = &d
|
||||
}
|
||||
}
|
||||
|
||||
func toTypeMeta(ext interface{}) (yaml.TypeMeta, bool) {
|
||||
m, ok := ext.(map[string]interface{})
|
||||
if !ok {
|
||||
return yaml.TypeMeta{}, false
|
||||
}
|
||||
|
||||
g := m[groupKey].(string)
|
||||
apiVersion := m[versionKey].(string)
|
||||
if g != "" {
|
||||
apiVersion = g + "/" + apiVersion
|
||||
}
|
||||
return yaml.TypeMeta{Kind: m[kindKey].(string), APIVersion: apiVersion}, true
|
||||
}
|
||||
|
||||
// Resolve resolves the reference against the global schema
|
||||
func Resolve(ref *spec.Ref, schema *spec.Schema) (*spec.Schema, error) {
|
||||
return resolve(schema, ref)
|
||||
}
|
||||
|
||||
// Schema returns the global schema
|
||||
func Schema() *spec.Schema {
|
||||
return rootSchema()
|
||||
}
|
||||
|
||||
// GetSchema parses s into a ResourceSchema, resolving References within the
|
||||
// global schema.
|
||||
func GetSchema(s string, schema *spec.Schema) (*ResourceSchema, error) {
|
||||
var sc spec.Schema
|
||||
if err := sc.UnmarshalJSON([]byte(s)); err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
if sc.Ref.String() != "" {
|
||||
r, err := Resolve(&sc.Ref, schema)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
sc = *r
|
||||
}
|
||||
|
||||
return &ResourceSchema{Schema: &sc}, nil
|
||||
}
|
||||
|
||||
// IsNamespaceScoped determines whether a resource is namespace or
|
||||
// cluster-scoped by looking at the information in the openapi schema.
|
||||
// The second return value tells whether the provided type could be found
|
||||
// in the openapi schema. If the value is false here, the scope of the
|
||||
// resource is not known. If the type if found, the first return value will
|
||||
// be true if the resource is namespace-scoped, and false if the type is
|
||||
// cluster-scoped.
|
||||
func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) {
|
||||
initSchema()
|
||||
isNamespaceScoped, found := globalSchema.namespaceabilityByResourceType[typeMeta]
|
||||
return isNamespaceScoped, found
|
||||
}
|
||||
|
||||
// SuppressBuiltInSchemaUse can be called to prevent using the built-in Kubernetes
|
||||
// schema as part of the global schema.
|
||||
// Must be called before the schema is used.
|
||||
func SuppressBuiltInSchemaUse() {
|
||||
globalSchema.noUseBuiltInSchema = true
|
||||
}
|
||||
|
||||
// Elements returns the Schema for the elements of an array.
|
||||
func (rs *ResourceSchema) Elements() *ResourceSchema {
|
||||
// load the schema from swagger.json
|
||||
initSchema()
|
||||
|
||||
if len(rs.Schema.Type) != 1 || rs.Schema.Type[0] != "array" {
|
||||
// either not an array, or array has multiple types
|
||||
return nil
|
||||
}
|
||||
if rs == nil || rs.Schema == nil || rs.Schema.Items == nil {
|
||||
// no-scheme for the items
|
||||
return nil
|
||||
}
|
||||
s := *rs.Schema.Items.Schema
|
||||
for s.Ref.String() != "" {
|
||||
sc, e := Resolve(&s.Ref, Schema())
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
s = *sc
|
||||
}
|
||||
return &ResourceSchema{Schema: &s}
|
||||
}
|
||||
|
||||
const Elements = "[]"
|
||||
|
||||
// Lookup calls either Field or Elements for each item in the path.
|
||||
// If the path item is "[]", then Elements is called, otherwise
|
||||
// Field is called.
|
||||
// If any Field or Elements call returns nil, then Lookup returns
|
||||
// nil immediately.
|
||||
func (rs *ResourceSchema) Lookup(path ...string) *ResourceSchema {
|
||||
s := rs
|
||||
for _, p := range path {
|
||||
if s == nil {
|
||||
break
|
||||
}
|
||||
if p == Elements {
|
||||
s = s.Elements()
|
||||
continue
|
||||
}
|
||||
s = s.Field(p)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Field returns the Schema for a field.
|
||||
func (rs *ResourceSchema) Field(field string) *ResourceSchema {
|
||||
// load the schema from swagger.json
|
||||
initSchema()
|
||||
|
||||
// locate the Schema
|
||||
s, found := rs.Schema.Properties[field]
|
||||
switch {
|
||||
case found:
|
||||
// no-op, continue with s as the schema
|
||||
case rs.Schema.AdditionalProperties != nil && rs.Schema.AdditionalProperties.Schema != nil:
|
||||
// map field type -- use Schema of the value
|
||||
// (the key doesn't matter, they all have the same value type)
|
||||
s = *rs.Schema.AdditionalProperties.Schema
|
||||
default:
|
||||
// no Schema found from either swagger.json or line comments
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolve the reference to the Schema if the Schema has one
|
||||
for s.Ref.String() != "" {
|
||||
sc, e := Resolve(&s.Ref, Schema())
|
||||
if e != nil {
|
||||
return nil
|
||||
}
|
||||
s = *sc
|
||||
}
|
||||
|
||||
// return the merged Schema
|
||||
return &ResourceSchema{Schema: &s}
|
||||
}
|
||||
|
||||
// PatchStrategyAndKeyList returns the patch strategy and complete merge key list
|
||||
func (rs *ResourceSchema) PatchStrategyAndKeyList() (string, []string) {
|
||||
ps, found := rs.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
|
||||
if !found {
|
||||
// empty patch strategy
|
||||
return "", []string{}
|
||||
}
|
||||
mkList, found := rs.Schema.Extensions[kubernetesMergeKeyMapList]
|
||||
if found {
|
||||
// mkList is []interface, convert to []string
|
||||
mkListStr := make([]string, len(mkList.([]interface{})))
|
||||
for i, v := range mkList.([]interface{}) {
|
||||
mkListStr[i] = v.(string)
|
||||
}
|
||||
return ps.(string), mkListStr
|
||||
}
|
||||
mk, found := rs.Schema.Extensions[kubernetesMergeKeyExtensionKey]
|
||||
if !found {
|
||||
// no mergeKey -- may be a primitive associative list (e.g. finalizers)
|
||||
return ps.(string), []string{}
|
||||
}
|
||||
return ps.(string), []string{mk.(string)}
|
||||
}
|
||||
|
||||
// PatchStrategyAndKey returns the patch strategy and merge key extensions
|
||||
func (rs *ResourceSchema) PatchStrategyAndKey() (string, string) {
|
||||
ps, found := rs.Schema.Extensions[kubernetesPatchStrategyExtensionKey]
|
||||
if !found {
|
||||
// empty patch strategy
|
||||
return "", ""
|
||||
}
|
||||
|
||||
mk, found := rs.Schema.Extensions[kubernetesMergeKeyExtensionKey]
|
||||
if !found {
|
||||
// no mergeKey -- may be a primitive associative list (e.g. finalizers)
|
||||
mk = ""
|
||||
}
|
||||
return ps.(string), mk.(string)
|
||||
}
|
||||
|
||||
const (
|
||||
// kubernetesOpenAPIDefaultVersion is the latest version number of the statically compiled in
|
||||
// OpenAPI schema for kubernetes built-in types
|
||||
kubernetesOpenAPIDefaultVersion = kubernetesapi.DefaultOpenAPI
|
||||
|
||||
// kustomizationAPIAssetName is the name of the asset containing the statically compiled in
|
||||
// OpenAPI definitions for Kustomization built-in types
|
||||
kustomizationAPIAssetName = "kustomizationapi/swagger.json"
|
||||
|
||||
// kubernetesGVKExtensionKey is the key to lookup the kubernetes group version kind extension
|
||||
// -- the extension is an array of objects containing a gvk
|
||||
kubernetesGVKExtensionKey = "x-kubernetes-group-version-kind"
|
||||
|
||||
// kubernetesMergeKeyExtensionKey is the key to lookup the kubernetes merge key extension
|
||||
// -- the extension is a string
|
||||
kubernetesMergeKeyExtensionKey = "x-kubernetes-patch-merge-key"
|
||||
|
||||
// kubernetesPatchStrategyExtensionKey is the key to lookup the kubernetes patch strategy
|
||||
// extension -- the extension is a string
|
||||
kubernetesPatchStrategyExtensionKey = "x-kubernetes-patch-strategy"
|
||||
|
||||
// kubernetesMergeKeyMapList is the list of merge keys when there needs to be multiple
|
||||
// -- the extension is an array of strings
|
||||
kubernetesMergeKeyMapList = "x-kubernetes-list-map-keys"
|
||||
|
||||
// groupKey is the key to lookup the group from the GVK extension
|
||||
groupKey = "group"
|
||||
// versionKey is the key to lookup the version from the GVK extension
|
||||
versionKey = "version"
|
||||
// kindKey is the the to lookup the kind from the GVK extension
|
||||
kindKey = "kind"
|
||||
)
|
||||
|
||||
// SetSchema sets the kubernetes OpenAPI schema version to use
|
||||
func SetSchema(openAPIField map[string]string, schema []byte, reset bool) error {
|
||||
// this should only be set once
|
||||
schemaIsSet := (kubernetesOpenAPIVersion != "") || customSchema != nil
|
||||
if schemaIsSet && !reset {
|
||||
return nil
|
||||
}
|
||||
|
||||
version, exists := openAPIField["version"]
|
||||
if exists && schema != nil {
|
||||
return fmt.Errorf("builtin version and custom schema provided, cannot use both")
|
||||
}
|
||||
|
||||
if schema != nil { // use custom schema
|
||||
customSchema = schema
|
||||
kubernetesOpenAPIVersion = "custom"
|
||||
return nil
|
||||
}
|
||||
|
||||
// use builtin version
|
||||
kubernetesOpenAPIVersion = strings.ReplaceAll(version, ".", "")
|
||||
if kubernetesOpenAPIVersion == "" {
|
||||
return nil
|
||||
}
|
||||
if _, ok := kubernetesapi.OpenAPIMustAsset[kubernetesOpenAPIVersion]; !ok {
|
||||
return fmt.Errorf("the specified OpenAPI version is not built in")
|
||||
}
|
||||
customSchema = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSchemaVersion returns what kubernetes OpenAPI version is being used
|
||||
func GetSchemaVersion() string {
|
||||
switch {
|
||||
case kubernetesOpenAPIVersion == "" && customSchema == nil:
|
||||
return kubernetesOpenAPIDefaultVersion
|
||||
case customSchema != nil:
|
||||
return "using custom schema from file provided"
|
||||
default:
|
||||
return kubernetesOpenAPIVersion
|
||||
}
|
||||
}
|
||||
|
||||
// initSchema parses the json schema
|
||||
func initSchema() {
|
||||
if globalSchema.schemaInit {
|
||||
return
|
||||
}
|
||||
globalSchema.schemaInit = true
|
||||
|
||||
if customSchema != nil {
|
||||
err := parse(customSchema)
|
||||
if err != nil {
|
||||
panic("invalid schema file")
|
||||
}
|
||||
if err = parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if kubernetesOpenAPIVersion == "" {
|
||||
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
|
||||
} else {
|
||||
parseBuiltinSchema(kubernetesOpenAPIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// parseBuiltinSchema calls parse to parse the json schemas
|
||||
func parseBuiltinSchema(version string) {
|
||||
if globalSchema.noUseBuiltInSchema {
|
||||
// don't parse the built in schema
|
||||
return
|
||||
}
|
||||
|
||||
// parse the swagger, this should never fail
|
||||
assetName := filepath.Join(
|
||||
"kubernetesapi",
|
||||
version,
|
||||
"swagger.json")
|
||||
|
||||
if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// parse parses and indexes a single json schema
|
||||
func parse(b []byte) error {
|
||||
var swagger spec.Swagger
|
||||
|
||||
if err := swagger.UnmarshalJSON(b); err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
AddDefinitions(swagger.Definitions)
|
||||
findNamespaceability(swagger.Paths)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findNamespaceability looks at the api paths for the resource to determine
|
||||
// if it is cluster-scoped or namespace-scoped. The gvk of the resource
|
||||
// for each path is found by looking at the x-kubernetes-group-version-kind
|
||||
// extension. If a path exists for the resource that contains a namespace path
|
||||
// parameter, the resource is namespace-scoped.
|
||||
func findNamespaceability(paths *spec.Paths) {
|
||||
if globalSchema.namespaceabilityByResourceType == nil {
|
||||
globalSchema.namespaceabilityByResourceType = make(map[yaml.TypeMeta]bool)
|
||||
}
|
||||
|
||||
if paths == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for path, pathInfo := range paths.Paths {
|
||||
if pathInfo.Get == nil {
|
||||
continue
|
||||
}
|
||||
gvk, found := pathInfo.Get.VendorExtensible.Extensions[kubernetesGVKExtensionKey]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
typeMeta, found := toTypeMeta(gvk)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(path, "namespaces/{namespace}") {
|
||||
// if we find a namespace path parameter, we just update the map
|
||||
// directly
|
||||
globalSchema.namespaceabilityByResourceType[typeMeta] = true
|
||||
} else if _, found := globalSchema.namespaceabilityByResourceType[typeMeta]; !found {
|
||||
// if the resource doesn't have the namespace path parameter, we
|
||||
// only add it to the map if it doesn't already exist.
|
||||
globalSchema.namespaceabilityByResourceType[typeMeta] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) {
|
||||
res, _, err := ref.GetPointer().Get(root)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
switch sch := res.(type) {
|
||||
case spec.Schema:
|
||||
return &sch, nil
|
||||
case *spec.Schema:
|
||||
return sch, nil
|
||||
case map[string]interface{}:
|
||||
b, err := json.Marshal(sch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newSch := new(spec.Schema)
|
||||
if err = json.Unmarshal(b, newSch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSch, nil
|
||||
default:
|
||||
return nil, errors.Wrap(fmt.Errorf("unknown type for the resolved reference"))
|
||||
}
|
||||
}
|
||||
|
||||
func rootSchema() *spec.Schema {
|
||||
initSchema()
|
||||
return &globalSchema.schema
|
||||
}
|
||||
64
vendor/sigs.k8s.io/kustomize/kyaml/sets/string.go
generated
vendored
Normal file
64
vendor/sigs.k8s.io/kustomize/kyaml/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sets
|
||||
|
||||
type String map[string]interface{}
|
||||
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s String) List() []string {
|
||||
var val []string
|
||||
for k := range s {
|
||||
val = append(val, k)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (s String) Has(val string) bool {
|
||||
_, found := s[val]
|
||||
return found
|
||||
}
|
||||
|
||||
func (s String) Insert(vals ...string) {
|
||||
for _, val := range vals {
|
||||
s[val] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s String) Difference(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
|
||||
func (s String) SymmetricDifference(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
for k := range s2 {
|
||||
if _, found := s[k]; !found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
|
||||
func (s String) Intersection(s2 String) String {
|
||||
s3 := String{}
|
||||
for k := range s {
|
||||
if _, found := s2[k]; found {
|
||||
s3.Insert(k)
|
||||
}
|
||||
}
|
||||
return s3
|
||||
}
|
||||
44
vendor/sigs.k8s.io/kustomize/kyaml/sets/stringlist.go
generated
vendored
Normal file
44
vendor/sigs.k8s.io/kustomize/kyaml/sets/stringlist.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sets
|
||||
|
||||
// StringList is a set, where each element of
|
||||
// the set is a string slice.
|
||||
type StringList [][]string
|
||||
|
||||
func (s StringList) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s StringList) Insert(val []string) StringList {
|
||||
if !s.Has(val) {
|
||||
return append(s, val)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s StringList) Has(val []string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range s {
|
||||
if isStringSliceEqual(s[i], val) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isStringSliceEqual(s []string, t []string) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i := range s {
|
||||
if s[i] != t[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
44
vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go
generated
vendored
Normal file
44
vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Expose the yaml.v3 functions so this package can be used as a replacement
|
||||
|
||||
type Decoder = yaml.Decoder
|
||||
type Encoder = yaml.Encoder
|
||||
type IsZeroer = yaml.IsZeroer
|
||||
type Kind = yaml.Kind
|
||||
type Marshaler = yaml.Marshaler
|
||||
type Node = yaml.Node
|
||||
type Style = yaml.Style
|
||||
type TypeError = yaml.TypeError
|
||||
type Unmarshaler = yaml.Unmarshaler
|
||||
|
||||
var Marshal = yaml.Marshal
|
||||
var Unmarshal = yaml.Unmarshal
|
||||
var NewDecoder = yaml.NewDecoder
|
||||
var NewEncoder = func(w io.Writer) *yaml.Encoder {
|
||||
e := yaml.NewEncoder(w)
|
||||
e.SetIndent(2)
|
||||
return e
|
||||
}
|
||||
|
||||
var AliasNode yaml.Kind = yaml.AliasNode
|
||||
var DocumentNode yaml.Kind = yaml.DocumentNode
|
||||
var MappingNode yaml.Kind = yaml.MappingNode
|
||||
var ScalarNode yaml.Kind = yaml.ScalarNode
|
||||
var SequenceNode yaml.Kind = yaml.SequenceNode
|
||||
|
||||
var DoubleQuotedStyle yaml.Style = yaml.DoubleQuotedStyle
|
||||
var FlowStyle yaml.Style = yaml.FlowStyle
|
||||
var FoldedStyle yaml.Style = yaml.FoldedStyle
|
||||
var LiteralStyle yaml.Style = yaml.LiteralStyle
|
||||
var SingleQuotedStyle yaml.Style = yaml.SingleQuotedStyle
|
||||
var TaggedStyle yaml.Style = yaml.TaggedStyle
|
||||
92
vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go
generated
vendored
Normal file
92
vendor/sigs.k8s.io/kustomize/kyaml/yaml/compatibility.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
y1_1 "gopkg.in/yaml.v2"
|
||||
y1_2 "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// typeToTag maps OpenAPI schema types to yaml 1.2 tags
|
||||
var typeToTag = map[string]string{
|
||||
"string": NodeTagString,
|
||||
"integer": NodeTagInt,
|
||||
"boolean": NodeTagBool,
|
||||
"number": NodeTagFloat,
|
||||
}
|
||||
|
||||
// FormatNonStringStyle makes sure that values which parse as non-string values in yaml 1.1
|
||||
// are correctly formatted given the Schema type.
|
||||
func FormatNonStringStyle(node *Node, schema spec.Schema) {
|
||||
if len(schema.Type) != 1 {
|
||||
return
|
||||
}
|
||||
t := schema.Type[0]
|
||||
|
||||
if !IsYaml1_1NonString(node) {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case t == "string" && schema.Format != "int-or-string":
|
||||
if (node.Style&DoubleQuotedStyle == 0) && (node.Style&SingleQuotedStyle == 0) {
|
||||
// must quote values so they are parsed as strings
|
||||
node.Style = DoubleQuotedStyle
|
||||
}
|
||||
case t == "boolean" || t == "integer" || t == "number":
|
||||
if (node.Style&DoubleQuotedStyle != 0) || (node.Style&SingleQuotedStyle != 0) {
|
||||
// must NOT quote the values so they aren't parsed as strings
|
||||
node.Style = 0
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
if tag, found := typeToTag[t]; found {
|
||||
// make sure the right tag is set
|
||||
node.Tag = tag
|
||||
}
|
||||
}
|
||||
|
||||
// IsYaml1_1NonString returns true if the value parses as a non-string value in yaml 1.1
|
||||
// when unquoted.
|
||||
//
|
||||
// Note: yaml 1.2 uses different keywords than yaml 1.1. Example: yaml 1.2 interprets
|
||||
// `field: on` and `field: "on"` as equivalent (both strings). However Yaml 1.1 interprets
|
||||
// `field: on` as on being a bool and `field: "on"` as on being a string.
|
||||
// If an input is read with `field: "on"`, and the style is changed from DoubleQuote to 0,
|
||||
// it will change the type of the field from a string to a bool. For this reason, fields
|
||||
// which are keywords in yaml 1.1 should never have their style changed, as it would break
|
||||
// backwards compatibility with yaml 1.1 -- which is what is used by the Kubernetes apiserver.
|
||||
func IsYaml1_1NonString(node *Node) bool {
|
||||
if node.Kind != y1_2.ScalarNode {
|
||||
// not a keyword
|
||||
return false
|
||||
}
|
||||
return IsValueNonString(node.Value)
|
||||
}
|
||||
|
||||
func IsValueNonString(value string) bool {
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(value, "\n") {
|
||||
// multi-line strings will fail to unmarshal
|
||||
return false
|
||||
}
|
||||
// check if the value will unmarshal into a non-string value using a yaml 1.1 parser
|
||||
var i1 interface{}
|
||||
if err := y1_1.Unmarshal([]byte(value), &i1); err != nil {
|
||||
return false
|
||||
}
|
||||
if reflect.TypeOf(i1) != stringType {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var stringType = reflect.TypeOf("string")
|
||||
30
vendor/sigs.k8s.io/kustomize/kyaml/yaml/const.go
generated
vendored
Normal file
30
vendor/sigs.k8s.io/kustomize/kyaml/yaml/const.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
const (
|
||||
// NodeTagNull is the tag set for a yaml.Document that contains no data;
|
||||
// e.g. it isn't a Map, Slice, Document, etc
|
||||
NodeTagNull = "!!null"
|
||||
NodeTagFloat = "!!float"
|
||||
NodeTagString = "!!str"
|
||||
NodeTagBool = "!!bool"
|
||||
NodeTagInt = "!!int"
|
||||
NodeTagMap = "!!map"
|
||||
NodeTagSeq = "!!seq"
|
||||
NodeTagEmpty = ""
|
||||
)
|
||||
|
||||
// Field names
|
||||
const (
|
||||
AnnotationsField = "annotations"
|
||||
APIVersionField = "apiVersion"
|
||||
KindField = "kind"
|
||||
MetadataField = "metadata"
|
||||
DataField = "data"
|
||||
BinaryDataField = "binaryData"
|
||||
NameField = "name"
|
||||
NamespaceField = "namespace"
|
||||
LabelsField = "labels"
|
||||
)
|
||||
121
vendor/sigs.k8s.io/kustomize/kyaml/yaml/datamap.go
generated
vendored
Normal file
121
vendor/sigs.k8s.io/kustomize/kyaml/yaml/datamap.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoConfigMapData(m map[string]string) error {
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
fldName, vrN := makeConfigMapValueRNode(m[k])
|
||||
if _, err := rn.Pipe(
|
||||
LookupCreate(MappingNode, fldName),
|
||||
SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoConfigMapBinaryData(m map[string]string) error {
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
_, vrN := makeConfigMapValueRNode(m[k])
|
||||
// we know this is binary data
|
||||
fldName := BinaryDataField
|
||||
if _, err := rn.Pipe(
|
||||
LookupCreate(MappingNode, fldName),
|
||||
SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeConfigMapValueRNode(s string) (field string, rN *RNode) {
|
||||
yN := &Node{Kind: ScalarNode}
|
||||
yN.Tag = NodeTagString
|
||||
if utf8.ValidString(s) {
|
||||
field = DataField
|
||||
yN.Value = s
|
||||
} else {
|
||||
field = BinaryDataField
|
||||
yN.Value = encodeBase64(s)
|
||||
}
|
||||
if strings.Contains(yN.Value, "\n") {
|
||||
yN.Style = LiteralStyle
|
||||
}
|
||||
return field, NewRNode(yN)
|
||||
}
|
||||
|
||||
func (rn *RNode) LoadMapIntoSecretData(m map[string]string) error {
|
||||
mapNode, err := rn.Pipe(LookupCreate(MappingNode, DataField))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, k := range SortedMapKeys(m) {
|
||||
vrN := makeSecretValueRNode(m[k])
|
||||
if _, err := mapNode.Pipe(SetField(k, vrN)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// In a secret, all data is base64 encoded, regardless of its conformance
|
||||
// or lack thereof to UTF-8.
|
||||
func makeSecretValueRNode(s string) *RNode {
|
||||
yN := &Node{Kind: ScalarNode}
|
||||
// Purposely don't use YAML tags to identify the data as being plain text or
|
||||
// binary. It kubernetes Secrets the values in the `data` map are expected
|
||||
// to be base64 encoded, and in ConfigMaps that same can be said for the
|
||||
// values in the `binaryData` field.
|
||||
yN.Tag = NodeTagString
|
||||
yN.Value = encodeBase64(s)
|
||||
if strings.Contains(yN.Value, "\n") {
|
||||
yN.Style = LiteralStyle
|
||||
}
|
||||
return NewRNode(yN)
|
||||
}
|
||||
|
||||
// encodeBase64 encodes s as base64 that is broken up into multiple lines
|
||||
// as appropriate for the resulting length.
|
||||
func encodeBase64(s string) string {
|
||||
const lineLen = 70
|
||||
encLen := base64.StdEncoding.EncodedLen(len(s))
|
||||
lines := encLen/lineLen + 1
|
||||
buf := make([]byte, encLen*2+lines)
|
||||
in := buf[0:encLen]
|
||||
out := buf[encLen:]
|
||||
base64.StdEncoding.Encode(in, []byte(s))
|
||||
k := 0
|
||||
for i := 0; i < len(in); i += lineLen {
|
||||
j := i + lineLen
|
||||
if j > len(in) {
|
||||
j = len(in)
|
||||
}
|
||||
k += copy(out[k:], in[i:j])
|
||||
if lines > 1 {
|
||||
out[k] = '\n'
|
||||
k++
|
||||
}
|
||||
}
|
||||
return string(out[:k])
|
||||
}
|
||||
49
vendor/sigs.k8s.io/kustomize/kyaml/yaml/doc.go
generated
vendored
Normal file
49
vendor/sigs.k8s.io/kustomize/kyaml/yaml/doc.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package yaml contains libraries for manipulating individual Kubernetes Resource
|
||||
// Configuration as yaml, keeping yaml structure and comments.
|
||||
//
|
||||
// Parsing Resources
|
||||
//
|
||||
// Typically Resources will be initialized as collections through the kio package libraries.
|
||||
// However it is possible to directly initialize Resources using Parse.
|
||||
// resource, err := yaml.Parse("apiVersion: apps/v1\nkind: Deployment")
|
||||
//
|
||||
// Processing Resources
|
||||
//
|
||||
// Individual Resources are manipulated using the Pipe and PipeE to apply Filter functions
|
||||
// to transform the Resource data.
|
||||
// err := resource.PipeE(yaml.SetAnnotation("key", "value"))
|
||||
//
|
||||
// If multiple Filter functions are provided to Pipe or PipeE, each function is applied to
|
||||
// the result of the last function -- e.g. yaml.Lookup(...), yaml.SetField(...)
|
||||
//
|
||||
// Field values may also be retrieved using Pipe.
|
||||
// annotationValue, err := resource.Pipe(yaml.GetAnnotation("key"))
|
||||
//
|
||||
// See http://www.linfo.org/filters.html for a definition of filters.
|
||||
//
|
||||
// Common Filters
|
||||
//
|
||||
// There are a number of standard filter functions provided by the yaml package.
|
||||
//
|
||||
// Working with annotations:
|
||||
// [AnnotationSetter{}, AnnotationGetter{}, AnnotationClearer{}]
|
||||
//
|
||||
// Working with fields by path:
|
||||
// [PathMatcher{}, PathGetter{}]
|
||||
//
|
||||
// Working with individual fields on Maps and Objects:
|
||||
// [FieldMatcher{}, FieldSetter{}, FieldGetter{}]
|
||||
//
|
||||
// Working with individual elements in Sequences:
|
||||
// [ElementAppender{}, ElementSetter{}, ElementMatcher{}]
|
||||
//
|
||||
// Writing Filters
|
||||
//
|
||||
// Users may implement their own filter functions. When doing so, can be necessary to work with
|
||||
// the RNode directly rather than through Pipe. RNode provides a number of functions for doing
|
||||
// so. See:
|
||||
// [GetMeta(), Fields(), Elements(), String()]
|
||||
package yaml
|
||||
146
vendor/sigs.k8s.io/kustomize/kyaml/yaml/filters.go
generated
vendored
Normal file
146
vendor/sigs.k8s.io/kustomize/kyaml/yaml/filters.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Filters is the list of serializable Pipeline Filters
|
||||
var Filters = map[string]func() Filter{
|
||||
"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
|
||||
"AnnotationGetter": func() Filter { return &AnnotationGetter{} },
|
||||
"AnnotationSetter": func() Filter { return &AnnotationSetter{} },
|
||||
"LabelSetter": func() Filter { return &LabelSetter{} },
|
||||
"ElementAppender": func() Filter { return &ElementAppender{} },
|
||||
"ElementMatcher": func() Filter { return &ElementMatcher{} },
|
||||
"FieldClearer": func() Filter { return &FieldClearer{} },
|
||||
"FilterMatcher": func() Filter { return &FilterMatcher{} },
|
||||
"FieldMatcher": func() Filter { return &FieldMatcher{} },
|
||||
"FieldSetter": func() Filter { return &FieldSetter{} },
|
||||
"PathGetter": func() Filter { return &PathGetter{} },
|
||||
"PathMatcher": func() Filter { return &PathMatcher{} },
|
||||
"Parser": func() Filter { return &Parser{} },
|
||||
"PrefixSetter": func() Filter { return &PrefixSetter{} },
|
||||
"ValueReplacer": func() Filter { return &ValueReplacer{} },
|
||||
"SuffixSetter": func() Filter { return &SuffixSetter{} },
|
||||
"TeePiper": func() Filter { return &TeePiper{} },
|
||||
}
|
||||
|
||||
// YFilter wraps the Filter interface so the filter can be represented as
|
||||
// data and can be unmarshalled into a struct from a yaml config file.
|
||||
// This allows Pipelines to be expressed as data rather than code.
|
||||
type YFilter struct {
|
||||
Filter
|
||||
}
|
||||
|
||||
func (y YFilter) MarshalYAML() (interface{}, error) {
|
||||
return y.Filter, nil
|
||||
}
|
||||
|
||||
func (y *YFilter) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
meta := &ResourceMeta{}
|
||||
if err := unmarshal(meta); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, found := Filters[meta.Kind]
|
||||
if !found {
|
||||
var knownFilters []string
|
||||
for k := range Filters {
|
||||
knownFilters = append(knownFilters, k)
|
||||
}
|
||||
sort.Strings(knownFilters)
|
||||
return fmt.Errorf("unsupported Filter Kind %s: may be one of: [%s]",
|
||||
meta.Kind, strings.Join(knownFilters, ","))
|
||||
}
|
||||
y.Filter = filter()
|
||||
|
||||
if err := unmarshal(y.Filter); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type YFilters []YFilter
|
||||
|
||||
func (y YFilters) Filters() []Filter {
|
||||
var f []Filter
|
||||
for i := range y {
|
||||
f = append(f, y[i].Filter)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
type FilterMatcher struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
// Filters are the set of Filters run by TeePiper.
|
||||
Filters YFilters `yaml:"pipeline,omitempty"`
|
||||
}
|
||||
|
||||
func (t FilterMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
v, err := rn.Pipe(t.Filters.Filters()...)
|
||||
if v == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// return the original input if the pipeline resolves to true
|
||||
return rn, err
|
||||
}
|
||||
|
||||
type ValueReplacer struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
StringMatch string `yaml:"stringMatch"`
|
||||
RegexMatch string `yaml:"regexMatch"`
|
||||
Replace string `yaml:"replace"`
|
||||
Count int `yaml:"count"`
|
||||
}
|
||||
|
||||
func (s ValueReplacer) Filter(object *RNode) (*RNode, error) {
|
||||
if s.Count == 0 {
|
||||
s.Count = -1
|
||||
}
|
||||
switch {
|
||||
case s.StringMatch != "":
|
||||
object.value.Value = strings.Replace(object.value.Value, s.StringMatch, s.Replace, s.Count)
|
||||
case s.RegexMatch != "":
|
||||
r, err := regexp.Compile(s.RegexMatch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ValueReplacer RegexMatch does not compile: %v", err)
|
||||
}
|
||||
object.value.Value = r.ReplaceAllString(object.value.Value, s.Replace)
|
||||
default:
|
||||
return nil, fmt.Errorf("ValueReplacer missing StringMatch and RegexMatch")
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
type PrefixSetter struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
func (s PrefixSetter) Filter(object *RNode) (*RNode, error) {
|
||||
if !strings.HasPrefix(object.value.Value, s.Value) {
|
||||
object.value.Value = s.Value + object.value.Value
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
|
||||
type SuffixSetter struct {
|
||||
Kind string `yaml:"kind"`
|
||||
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
func (s SuffixSetter) Filter(object *RNode) (*RNode, error) {
|
||||
if !strings.HasSuffix(object.value.Value, s.Value) {
|
||||
object.value.Value += s.Value
|
||||
}
|
||||
return object, nil
|
||||
}
|
||||
769
vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go
generated
vendored
Normal file
769
vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go
generated
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// Append creates an ElementAppender
|
||||
func Append(elements ...*yaml.Node) ElementAppender {
|
||||
return ElementAppender{Elements: elements}
|
||||
}
|
||||
|
||||
// ElementAppender adds all element to a SequenceNode's Content.
|
||||
// Returns Elements[0] if len(Elements) == 1, otherwise returns nil.
|
||||
type ElementAppender struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Elem is the value to append.
|
||||
Elements []*yaml.Node `yaml:"elements,omitempty"`
|
||||
}
|
||||
|
||||
func (a ElementAppender) Filter(rn *RNode) (*RNode, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range a.Elements {
|
||||
rn.YNode().Content = append(rn.Content(), a.Elements[i])
|
||||
}
|
||||
if len(a.Elements) == 1 {
|
||||
return NewRNode(a.Elements[0]), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ElementSetter sets the value for an Element in an associative list.
|
||||
// ElementSetter will append, replace or delete an element in an associative list.
|
||||
// To append, user a key-value pair that doesn't exist in the sequence. this
|
||||
// behavior is intended to handle the case that not matching element found. It's
|
||||
// not designed for this purpose. To append an element, please use ElementAppender.
|
||||
// To replace, set the key-value pair and a non-nil Element.
|
||||
// To delete, set the key-value pair and leave the Element as nil.
|
||||
// Every key must have a corresponding value.
|
||||
type ElementSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Element is the new value to set -- remove the existing element if nil
|
||||
Element *Node
|
||||
|
||||
// Key is a list of fields on the elements. It is used to find matching elements to
|
||||
// update / delete
|
||||
Keys []string
|
||||
|
||||
// Value is a list of field values on the elements corresponding to the keys. It is
|
||||
// used to find matching elements to update / delete.
|
||||
Values []string
|
||||
}
|
||||
|
||||
// isMappingNode returns whether node is a mapping node
|
||||
func (e ElementSetter) isMappingNode(node *RNode) bool {
|
||||
return ErrorIfInvalid(node, yaml.MappingNode) == nil
|
||||
}
|
||||
|
||||
// isMappingSetter returns is this setter intended to set a mapping node
|
||||
func (e ElementSetter) isMappingSetter() bool {
|
||||
return len(e.Keys) > 0 && e.Keys[0] != "" &&
|
||||
len(e.Values) > 0 && e.Values[0] != ""
|
||||
}
|
||||
|
||||
func (e ElementSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
if len(e.Keys) == 0 {
|
||||
e.Keys = append(e.Keys, "")
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// build the new Content slice
|
||||
var newContent []*yaml.Node
|
||||
matchingElementFound := false
|
||||
for i := range rn.YNode().Content {
|
||||
elem := rn.Content()[i]
|
||||
newNode := NewRNode(elem)
|
||||
|
||||
// empty elements are not valid -- they at least need an associative key
|
||||
if IsMissingOrNull(newNode) || IsEmptyMap(newNode) {
|
||||
continue
|
||||
}
|
||||
// keep non-mapping node in the Content when we want to match a mapping.
|
||||
if !e.isMappingNode(newNode) && e.isMappingSetter() {
|
||||
newContent = append(newContent, elem)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if this is the element we are matching
|
||||
var val *RNode
|
||||
var err error
|
||||
found := true
|
||||
for j := range e.Keys {
|
||||
if j < len(e.Values) {
|
||||
val, err = newNode.Pipe(FieldMatcher{Name: e.Keys[j], StringValue: e.Values[j]})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val == nil {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// not the element we are looking for, keep it in the Content
|
||||
if len(e.Values) > 0 {
|
||||
newContent = append(newContent, elem)
|
||||
}
|
||||
continue
|
||||
}
|
||||
matchingElementFound = true
|
||||
|
||||
// deletion operation -- remove the element from the new Content
|
||||
if e.Element == nil {
|
||||
continue
|
||||
}
|
||||
// replace operation -- replace the element in the Content
|
||||
newContent = append(newContent, e.Element)
|
||||
}
|
||||
rn.YNode().Content = newContent
|
||||
|
||||
// deletion operation -- return nil
|
||||
if IsMissingOrNull(NewRNode(e.Element)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// append operation -- add the element to the Content
|
||||
if !matchingElementFound {
|
||||
rn.YNode().Content = append(rn.YNode().Content, e.Element)
|
||||
}
|
||||
|
||||
return NewRNode(e.Element), nil
|
||||
}
|
||||
|
||||
// GetElementByIndex will return a Filter which can be applied to a sequence
|
||||
// node to get the element specified by the index
|
||||
func GetElementByIndex(index int) ElementIndexer {
|
||||
return ElementIndexer{Index: index}
|
||||
}
|
||||
|
||||
// ElementIndexer picks the element with a specified index. Index starts from
|
||||
// 0 to len(list) - 1. a hyphen ("-") means the last index.
|
||||
type ElementIndexer struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
// Filter implements Filter
|
||||
func (i ElementIndexer) Filter(rn *RNode) (*RNode, error) {
|
||||
// rn.Elements will return error if rn is not a sequence node.
|
||||
elems, err := rn.Elements()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i.Index < 0 {
|
||||
return elems[len(elems)-1], nil
|
||||
}
|
||||
if i.Index >= len(elems) {
|
||||
return nil, nil
|
||||
}
|
||||
return elems[i.Index], nil
|
||||
}
|
||||
|
||||
// Clear returns a FieldClearer
|
||||
func Clear(name string) FieldClearer {
|
||||
return FieldClearer{Name: name}
|
||||
}
|
||||
|
||||
// FieldClearer removes the field or map key.
|
||||
// Returns a RNode with the removed field or map entry.
|
||||
type FieldClearer struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name is the name of the field or key in the map.
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
IfEmpty bool `yaml:"ifEmpty,omitempty"`
|
||||
}
|
||||
|
||||
func (c FieldClearer) Filter(rn *RNode) (*RNode, error) {
|
||||
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(rn.Content()); i += 2 {
|
||||
// if name matches, remove these 2 elements from the list because
|
||||
// they are treated as a fieldName/fieldValue pair.
|
||||
if rn.Content()[i].Value == c.Name {
|
||||
if c.IfEmpty {
|
||||
if len(rn.Content()[i+1].Content) > 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// save the item we are about to remove
|
||||
removed := NewRNode(rn.Content()[i+1])
|
||||
if len(rn.YNode().Content) > i+2 {
|
||||
l := len(rn.YNode().Content)
|
||||
// remove from the middle of the list
|
||||
rn.YNode().Content = rn.Content()[:i]
|
||||
rn.YNode().Content = append(
|
||||
rn.YNode().Content,
|
||||
rn.Content()[i+2:l]...)
|
||||
} else {
|
||||
// remove from the end of the list
|
||||
rn.YNode().Content = rn.Content()[:i]
|
||||
}
|
||||
|
||||
// return the removed field name and value
|
||||
return removed, nil
|
||||
}
|
||||
}
|
||||
// nothing removed
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func MatchElement(field, value string) ElementMatcher {
|
||||
return ElementMatcher{Keys: []string{field}, Values: []string{value}}
|
||||
}
|
||||
|
||||
func MatchElementList(keys []string, values []string) ElementMatcher {
|
||||
return ElementMatcher{Keys: keys, Values: values}
|
||||
}
|
||||
|
||||
func GetElementByKey(key string) ElementMatcher {
|
||||
return ElementMatcher{Keys: []string{key}, MatchAnyValue: true}
|
||||
}
|
||||
|
||||
// ElementMatcher returns the first element from a Sequence matching the
|
||||
// specified key-value pairs. If there's no match, and no configuration error,
|
||||
// the matcher returns nil, nil.
|
||||
type ElementMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Keys are the list of fields upon which to match this element.
|
||||
Keys []string
|
||||
|
||||
// Values are the list of values upon which to match this element.
|
||||
Values []string
|
||||
|
||||
// Create will create the Element if it is not found
|
||||
Create *RNode `yaml:"create,omitempty"`
|
||||
|
||||
// MatchAnyValue indicates that matcher should only consider the key and ignore
|
||||
// the actual value in the list. Values must be empty when MatchAnyValue is
|
||||
// set to true.
|
||||
MatchAnyValue bool `yaml:"noValue,omitempty"`
|
||||
}
|
||||
|
||||
func (e ElementMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
if len(e.Keys) == 0 {
|
||||
e.Keys = append(e.Keys, "")
|
||||
}
|
||||
if len(e.Values) == 0 {
|
||||
e.Values = append(e.Values, "")
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, yaml.SequenceNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.MatchAnyValue && len(e.Values) != 0 && e.Values[0] != "" {
|
||||
return nil, fmt.Errorf("Values must be empty when MatchAnyValue is set to true")
|
||||
}
|
||||
|
||||
// SequenceNode Content is a slice of ScalarNodes. Each ScalarNode has a
|
||||
// YNode containing the primitive data.
|
||||
if len(e.Keys) == 0 || len(e.Keys[0]) == 0 {
|
||||
for i := range rn.Content() {
|
||||
if rn.Content()[i].Value == e.Values[0] {
|
||||
return &RNode{value: rn.Content()[i]}, nil
|
||||
}
|
||||
}
|
||||
if e.Create != nil {
|
||||
return rn.Pipe(Append(e.Create.YNode()))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SequenceNode Content is a slice of MappingNodes. Each MappingNode has Content
|
||||
// with a slice of key-value pairs containing the fields.
|
||||
for i := range rn.Content() {
|
||||
// cast the entry to a RNode so we can operate on it
|
||||
elem := NewRNode(rn.Content()[i])
|
||||
var field *RNode
|
||||
var err error
|
||||
|
||||
// only check mapping node
|
||||
if err = ErrorIfInvalid(elem, yaml.MappingNode); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !e.MatchAnyValue && len(e.Keys) != len(e.Values) {
|
||||
return nil, fmt.Errorf("length of keys must equal length of values when MatchAnyValue is false")
|
||||
}
|
||||
|
||||
matchesElement := true
|
||||
for i := range e.Keys {
|
||||
if e.MatchAnyValue {
|
||||
field, err = elem.Pipe(Get(e.Keys[i]))
|
||||
} else {
|
||||
field, err = elem.Pipe(MatchField(e.Keys[i], e.Values[i]))
|
||||
}
|
||||
if !IsFoundOrError(field, err) {
|
||||
// this is not the element we are looking for
|
||||
matchesElement = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if matchesElement {
|
||||
return elem, err
|
||||
}
|
||||
}
|
||||
|
||||
// create the element
|
||||
if e.Create != nil {
|
||||
return rn.Pipe(Append(e.Create.YNode()))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func Get(name string) FieldMatcher {
|
||||
return FieldMatcher{Name: name}
|
||||
}
|
||||
|
||||
func MatchField(name, value string) FieldMatcher {
|
||||
return FieldMatcher{Name: name, Value: NewScalarRNode(value)}
|
||||
}
|
||||
|
||||
func Match(value string) FieldMatcher {
|
||||
return FieldMatcher{Value: NewScalarRNode(value)}
|
||||
}
|
||||
|
||||
// FieldMatcher returns the value of a named field or map entry.
|
||||
type FieldMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name of the field to return
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// YNode of the field to return.
|
||||
// Optional. Will only need to match field name if unset.
|
||||
Value *RNode `yaml:"value,omitempty"`
|
||||
|
||||
StringValue string `yaml:"stringValue,omitempty"`
|
||||
|
||||
StringRegexValue string `yaml:"stringRegexValue,omitempty"`
|
||||
|
||||
// Create will cause the field to be created with this value
|
||||
// if it is set.
|
||||
Create *RNode `yaml:"create,omitempty"`
|
||||
}
|
||||
|
||||
func (f FieldMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
if f.StringValue != "" && f.Value == nil {
|
||||
f.Value = NewScalarRNode(f.StringValue)
|
||||
}
|
||||
|
||||
// never match nil or null fields
|
||||
if IsMissingOrNull(rn) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if f.Name == "" {
|
||||
if err := ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case f.StringRegexValue != "":
|
||||
// TODO(pwittrock): pre-compile this when unmarshalling and cache to a field
|
||||
rg, err := regexp.Compile(f.StringRegexValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if match := rg.MatchString(rn.value.Value); match {
|
||||
return rn, nil
|
||||
}
|
||||
return nil, nil
|
||||
case GetValue(rn) == GetValue(f.Value):
|
||||
return rn, nil
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := ErrorIfInvalid(rn, yaml.MappingNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(rn.Content()); i = IncrementFieldIndex(i) {
|
||||
isMatchingField := rn.Content()[i].Value == f.Name
|
||||
if isMatchingField {
|
||||
requireMatchFieldValue := f.Value != nil
|
||||
if !requireMatchFieldValue || rn.Content()[i+1].Value == f.Value.YNode().Value {
|
||||
return NewRNode(rn.Content()[i+1]), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.Create != nil {
|
||||
return rn.Pipe(SetField(f.Name, f.Create))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path.
|
||||
func Lookup(path ...string) PathGetter {
|
||||
return PathGetter{Path: path}
|
||||
}
|
||||
|
||||
// Lookup returns a PathGetter to lookup a field by its path and create it if it doesn't already
|
||||
// exist.
|
||||
func LookupCreate(kind yaml.Kind, path ...string) PathGetter {
|
||||
return PathGetter{Path: path, Create: kind}
|
||||
}
|
||||
|
||||
// PathGetter returns the RNode under Path.
|
||||
type PathGetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Path is a slice of parts leading to the RNode to lookup.
|
||||
// Each path part may be one of:
|
||||
// * FieldMatcher -- e.g. "spec"
|
||||
// * Map Key -- e.g. "app.k8s.io/version"
|
||||
// * List Entry -- e.g. "[name=nginx]" or "[=-jar]" or "0" or "-"
|
||||
//
|
||||
// Map Keys and Fields are equivalent.
|
||||
// See FieldMatcher for more on Fields and Map Keys.
|
||||
//
|
||||
// List Entries can be specified as map entry to match [fieldName=fieldValue]
|
||||
// or a positional index like 0 to get the element. - (unquoted hyphen) is
|
||||
// special and means the last element.
|
||||
//
|
||||
// See Elem for more on List Entries.
|
||||
//
|
||||
// Examples:
|
||||
// * spec.template.spec.container with matching name: [name=nginx]
|
||||
// * spec.template.spec.container.argument matching a value: [=-jar]
|
||||
Path []string `yaml:"path,omitempty"`
|
||||
|
||||
// Create will cause missing path parts to be created as they are walked.
|
||||
//
|
||||
// * The leaf Node (final path) will be created with a Kind matching Create
|
||||
// * Intermediary Nodes will be created as either a MappingNodes or
|
||||
// SequenceNodes as appropriate for each's Path location.
|
||||
// * If a list item is specified by a index (an offset or "-"), this item will
|
||||
// not be created even Create is set.
|
||||
Create yaml.Kind `yaml:"create,omitempty"`
|
||||
|
||||
// Style is the style to apply to created value Nodes.
|
||||
// Created key Nodes keep an unspecified Style.
|
||||
Style yaml.Style `yaml:"style,omitempty"`
|
||||
}
|
||||
|
||||
func (l PathGetter) Filter(rn *RNode) (*RNode, error) {
|
||||
var err error
|
||||
fieldPath := append([]string{}, rn.FieldPath()...)
|
||||
match := rn
|
||||
|
||||
// iterate over path until encountering an error or missing value
|
||||
l.Path = cleanPath(l.Path)
|
||||
for i := range l.Path {
|
||||
var part, nextPart string
|
||||
part = l.Path[i]
|
||||
if len(l.Path) > i+1 {
|
||||
nextPart = l.Path[i+1]
|
||||
}
|
||||
var fltr Filter
|
||||
fltr, err = l.getFilter(part, nextPart, &fieldPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
match, err = match.Pipe(fltr)
|
||||
if IsMissingOrError(match, err) {
|
||||
return nil, err
|
||||
}
|
||||
match.AppendToFieldPath(fieldPath...)
|
||||
}
|
||||
return match, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) getFilter(part, nextPart string, fieldPath *[]string) (Filter, error) {
|
||||
idx, err := strconv.Atoi(part)
|
||||
switch {
|
||||
case err == nil:
|
||||
// part is a number
|
||||
if idx < 0 {
|
||||
return nil, fmt.Errorf("array index %d cannot be negative", idx)
|
||||
}
|
||||
return GetElementByIndex(idx), nil
|
||||
case part == "-":
|
||||
// part is a hyphen
|
||||
return GetElementByIndex(-1), nil
|
||||
case IsListIndex(part):
|
||||
// part is surrounded by brackets
|
||||
return l.elemFilter(part)
|
||||
default:
|
||||
// mapping node
|
||||
*fieldPath = append(*fieldPath, part)
|
||||
return l.fieldFilter(part, l.getKind(nextPart))
|
||||
}
|
||||
}
|
||||
|
||||
func (l PathGetter) elemFilter(part string) (Filter, error) {
|
||||
var match *RNode
|
||||
name, value, err := SplitIndexNameValue(part)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
if !IsCreate(l.Create) {
|
||||
return MatchElement(name, value), nil
|
||||
}
|
||||
|
||||
var elem *RNode
|
||||
primitiveElement := len(name) == 0
|
||||
if primitiveElement {
|
||||
// append a ScalarNode
|
||||
elem = NewScalarRNode(value)
|
||||
elem.YNode().Style = l.Style
|
||||
match = elem
|
||||
} else {
|
||||
// append a MappingNode
|
||||
match = NewRNode(&yaml.Node{Kind: yaml.ScalarNode, Value: value, Style: l.Style})
|
||||
elem = NewRNode(&yaml.Node{
|
||||
Kind: yaml.MappingNode,
|
||||
Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: name}, match.YNode()},
|
||||
Style: l.Style,
|
||||
})
|
||||
}
|
||||
// Append the Node
|
||||
return ElementMatcher{Keys: []string{name}, Values: []string{value}, Create: elem}, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) fieldFilter(
|
||||
name string, kind yaml.Kind) (Filter, error) {
|
||||
if !IsCreate(l.Create) {
|
||||
return Get(name), nil
|
||||
}
|
||||
return FieldMatcher{Name: name, Create: &RNode{value: &yaml.Node{Kind: kind, Style: l.Style}}}, nil
|
||||
}
|
||||
|
||||
func (l PathGetter) getKind(nextPart string) yaml.Kind {
|
||||
if IsListIndex(nextPart) {
|
||||
// if nextPart is of the form [a=b], then it is an index into a Sequence
|
||||
// so the current part must be a SequenceNode
|
||||
return yaml.SequenceNode
|
||||
}
|
||||
if nextPart == "" {
|
||||
// final name in the path, use the l.Create defined Kind
|
||||
return l.Create
|
||||
}
|
||||
|
||||
// non-sequence intermediate Node
|
||||
return yaml.MappingNode
|
||||
}
|
||||
|
||||
func SetField(name string, value *RNode) FieldSetter {
|
||||
return FieldSetter{Name: name, Value: value}
|
||||
}
|
||||
|
||||
func Set(value *RNode) FieldSetter {
|
||||
return FieldSetter{Value: value}
|
||||
}
|
||||
|
||||
// FieldSetter sets a field or map entry to a value.
|
||||
type FieldSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Name is the name of the field or key to lookup in a MappingNode.
|
||||
// If Name is unspecified, and the input is a ScalarNode, FieldSetter will set the
|
||||
// value on the ScalarNode.
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// Comments for the field
|
||||
Comments Comments `yaml:"comments,omitempty"`
|
||||
|
||||
// Value is the value to set.
|
||||
// Optional if Kind is set.
|
||||
Value *RNode `yaml:"value,omitempty"`
|
||||
|
||||
StringValue string `yaml:"stringValue,omitempty"`
|
||||
|
||||
// OverrideStyle can be set to override the style of the existing node
|
||||
// when setting it. Otherwise, if an existing node is found, the style is
|
||||
// retained.
|
||||
OverrideStyle bool `yaml:"overrideStyle,omitempty"`
|
||||
}
|
||||
|
||||
func (s FieldSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
if s.StringValue != "" && s.Value == nil {
|
||||
s.Value = NewScalarRNode(s.StringValue)
|
||||
}
|
||||
|
||||
if s.Name == "" {
|
||||
if err := ErrorIfInvalid(rn, yaml.ScalarNode); err != nil {
|
||||
return rn, err
|
||||
}
|
||||
if IsMissingOrNull(s.Value) {
|
||||
return rn, nil
|
||||
}
|
||||
// only apply the style if there is not an existing style
|
||||
// or we want to override it
|
||||
if !s.OverrideStyle || s.Value.YNode().Style == 0 {
|
||||
// keep the original style if it exists
|
||||
s.Value.YNode().Style = rn.YNode().Style
|
||||
}
|
||||
rn.SetYNode(s.Value.YNode())
|
||||
return rn, nil
|
||||
}
|
||||
|
||||
// Clear the field if it is empty, or explicitly null
|
||||
if s.Value == nil || s.Value.IsTaggedNull() {
|
||||
return rn.Pipe(Clear(s.Name))
|
||||
}
|
||||
|
||||
field, err := rn.Pipe(FieldMatcher{Name: s.Name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if field != nil {
|
||||
// only apply the style if there is not an existing style
|
||||
// or we want to override it
|
||||
if !s.OverrideStyle || field.YNode().Style == 0 {
|
||||
// keep the original style if it exists
|
||||
s.Value.YNode().Style = field.YNode().Style
|
||||
}
|
||||
// need to def ref the Node since field is ephemeral
|
||||
field.SetYNode(s.Value.YNode())
|
||||
return field, nil
|
||||
}
|
||||
|
||||
// create the field
|
||||
rn.YNode().Content = append(
|
||||
rn.YNode().Content,
|
||||
&yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Value: s.Name,
|
||||
HeadComment: s.Comments.HeadComment,
|
||||
LineComment: s.Comments.LineComment,
|
||||
FootComment: s.Comments.FootComment,
|
||||
},
|
||||
s.Value.YNode())
|
||||
return s.Value, nil
|
||||
}
|
||||
|
||||
// Tee calls the provided Filters, and returns its argument rather than the result
|
||||
// of the filters.
|
||||
// May be used to fork sub-filters from a call.
|
||||
// e.g. locate field, set value; locate another field, set another value
|
||||
func Tee(filters ...Filter) Filter {
|
||||
return TeePiper{Filters: filters}
|
||||
}
|
||||
|
||||
// TeePiper Calls a slice of Filters and returns its input.
|
||||
// May be used to fork sub-filters from a call.
|
||||
// e.g. locate field, set value; locate another field, set another value
|
||||
type TeePiper struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Filters are the set of Filters run by TeePiper.
|
||||
Filters []Filter `yaml:"filters,omitempty"`
|
||||
}
|
||||
|
||||
func (t TeePiper) Filter(rn *RNode) (*RNode, error) {
|
||||
_, err := rn.Pipe(t.Filters...)
|
||||
return rn, err
|
||||
}
|
||||
|
||||
// IsCreate returns true if kind is specified
|
||||
func IsCreate(kind yaml.Kind) bool {
|
||||
return kind != 0
|
||||
}
|
||||
|
||||
// IsMissingOrError returns true if rn is NOT found or err is non-nil
|
||||
func IsMissingOrError(rn *RNode, err error) bool {
|
||||
return rn == nil || err != nil
|
||||
}
|
||||
|
||||
// IsFoundOrError returns true if rn is found or err is non-nil
|
||||
func IsFoundOrError(rn *RNode, err error) bool {
|
||||
return rn != nil || err != nil
|
||||
}
|
||||
|
||||
func ErrorIfAnyInvalidAndNonNull(kind yaml.Kind, rn ...*RNode) error {
|
||||
for i := range rn {
|
||||
if IsMissingOrNull(rn[i]) {
|
||||
continue
|
||||
}
|
||||
if err := ErrorIfInvalid(rn[i], kind); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var nodeTypeIndex = map[yaml.Kind]string{
|
||||
yaml.SequenceNode: "SequenceNode",
|
||||
yaml.MappingNode: "MappingNode",
|
||||
yaml.ScalarNode: "ScalarNode",
|
||||
yaml.DocumentNode: "DocumentNode",
|
||||
yaml.AliasNode: "AliasNode",
|
||||
}
|
||||
|
||||
func ErrorIfInvalid(rn *RNode, kind yaml.Kind) error {
|
||||
if IsMissingOrNull(rn) {
|
||||
// node has no type, pass validation
|
||||
return nil
|
||||
}
|
||||
|
||||
if rn.YNode().Kind != kind {
|
||||
s, _ := rn.String()
|
||||
return errors.Errorf(
|
||||
"wrong Node Kind for %s expected: %v was %v: value: {%s}",
|
||||
strings.Join(rn.FieldPath(), "."),
|
||||
nodeTypeIndex[kind], nodeTypeIndex[rn.YNode().Kind], strings.TrimSpace(s))
|
||||
}
|
||||
|
||||
if kind == yaml.MappingNode {
|
||||
if len(rn.YNode().Content)%2 != 0 {
|
||||
return errors.Errorf(
|
||||
"yaml MappingNodes must have even length contents: %v", spew.Sdump(rn))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsListIndex returns true if p is an index into a Val.
|
||||
// e.g. [fieldName=fieldValue]
|
||||
// e.g. [=primitiveValue]
|
||||
func IsListIndex(p string) bool {
|
||||
return strings.HasPrefix(p, "[") && strings.HasSuffix(p, "]")
|
||||
}
|
||||
|
||||
// SplitIndexNameValue splits a lookup part Val index into the field name
|
||||
// and field value to match.
|
||||
// e.g. splits [name=nginx] into (name, nginx)
|
||||
// e.g. splits [=-jar] into ("", -jar)
|
||||
func SplitIndexNameValue(p string) (string, string, error) {
|
||||
elem := strings.TrimSuffix(p, "]")
|
||||
elem = strings.TrimPrefix(elem, "[")
|
||||
parts := strings.SplitN(elem, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
return "", "", fmt.Errorf("list path element must contain fieldName=fieldValue for element to match")
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
// IncrementFieldIndex increments i to point to the next field name element in
|
||||
// a slice of Contents.
|
||||
func IncrementFieldIndex(i int) int {
|
||||
return i + 2
|
||||
}
|
||||
43
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/copied.deepcopy.go
generated
vendored
Normal file
43
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/copied.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/zz_generated.deepcopy.go
|
||||
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Requirement) DeepCopyInto(out *Requirement) {
|
||||
*out = *in
|
||||
if in.strValues != nil {
|
||||
in, out := &in.strValues, &out.strValues
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Requirement.
|
||||
func (in *Requirement) DeepCopy() *Requirement {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Requirement)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
192
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/labels.go
generated
vendored
Normal file
192
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/labels.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/labels.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Labels allows you to present labels independently from their storage.
|
||||
type Labels interface {
|
||||
// Has returns whether the provided label exists.
|
||||
Has(label string) (exists bool)
|
||||
|
||||
// Get returns the value for the provided label.
|
||||
Get(label string) (value string)
|
||||
}
|
||||
|
||||
// Set is a map of label:value. It implements Labels.
|
||||
type Set map[string]string
|
||||
|
||||
// String returns all labels listed as a human readable string.
|
||||
// Conveniently, exactly the format that ParseSelector takes.
|
||||
func (ls Set) String() string {
|
||||
selector := make([]string, 0, len(ls))
|
||||
for key, value := range ls {
|
||||
selector = append(selector, key+"="+value)
|
||||
}
|
||||
// Sort for determinism.
|
||||
sort.StringSlice(selector).Sort()
|
||||
return strings.Join(selector, ",")
|
||||
}
|
||||
|
||||
// Has returns whether the provided label exists in the map.
|
||||
func (ls Set) Has(label string) bool {
|
||||
_, exists := ls[label]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Get returns the value in the map for the provided label.
|
||||
func (ls Set) Get(label string) string {
|
||||
return ls[label]
|
||||
}
|
||||
|
||||
// AsSelector converts labels into a selectors. It does not
|
||||
// perform any validation, which means the server will reject
|
||||
// the request if the Set contains invalid values.
|
||||
func (ls Set) AsSelector() Selector {
|
||||
return SelectorFromSet(ls)
|
||||
}
|
||||
|
||||
// AsValidatedSelector converts labels into a selectors.
|
||||
// The Set is validated client-side, which allows to catch errors early.
|
||||
func (ls Set) AsValidatedSelector() (Selector, error) {
|
||||
return ValidatedSelectorFromSet(ls)
|
||||
}
|
||||
|
||||
// AsSelectorPreValidated converts labels into a selector, but
|
||||
// assumes that labels are already validated and thus doesn't
|
||||
// perform any validation.
|
||||
// According to our measurements this is significantly faster
|
||||
// in codepaths that matter at high scale.
|
||||
func (ls Set) AsSelectorPreValidated() Selector {
|
||||
return SelectorFromValidatedSet(ls)
|
||||
}
|
||||
|
||||
// FormatLabels convert label map into plain string
|
||||
func FormatLabels(labelMap map[string]string) string {
|
||||
l := Set(labelMap).String()
|
||||
if l == "" {
|
||||
l = "<none>"
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Conflicts takes 2 maps and returns true if there a key match between
|
||||
// the maps but the value doesn't match, and returns false in other cases
|
||||
func Conflicts(labels1, labels2 Set) bool {
|
||||
small := labels1
|
||||
big := labels2
|
||||
if len(labels2) < len(labels1) {
|
||||
small = labels2
|
||||
big = labels1
|
||||
}
|
||||
|
||||
for k, v := range small {
|
||||
if val, match := big[k]; match {
|
||||
if val != v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Merge combines given maps, and does not check for any conflicts
|
||||
// between the maps. In case of conflicts, second map (labels2) wins
|
||||
func Merge(labels1, labels2 Set) Set {
|
||||
mergedMap := Set{}
|
||||
|
||||
for k, v := range labels1 {
|
||||
mergedMap[k] = v
|
||||
}
|
||||
for k, v := range labels2 {
|
||||
mergedMap[k] = v
|
||||
}
|
||||
return mergedMap
|
||||
}
|
||||
|
||||
// Equals returns true if the given maps are equal
|
||||
func Equals(labels1, labels2 Set) bool {
|
||||
if len(labels1) != len(labels2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, v := range labels1 {
|
||||
value, ok := labels2[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if value != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AreLabelsInWhiteList verifies if the provided label list
|
||||
// is in the provided whitelist and returns true, otherwise false.
|
||||
func AreLabelsInWhiteList(labels, whitelist Set) bool {
|
||||
if len(whitelist) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for k, v := range labels {
|
||||
value, ok := whitelist[k]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if value != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ConvertSelectorToLabelsMap converts selector string to labels map
|
||||
// and validates keys and values
|
||||
func ConvertSelectorToLabelsMap(selector string) (Set, error) {
|
||||
labelsMap := Set{}
|
||||
|
||||
if len(selector) == 0 {
|
||||
return labelsMap, nil
|
||||
}
|
||||
|
||||
labels := strings.Split(selector, ",")
|
||||
for _, label := range labels {
|
||||
l := strings.Split(label, "=")
|
||||
if len(l) != 2 {
|
||||
return labelsMap, fmt.Errorf("invalid selector: %s", l)
|
||||
}
|
||||
key := strings.TrimSpace(l[0])
|
||||
if err := validateLabelKey(key); err != nil {
|
||||
return labelsMap, err
|
||||
}
|
||||
value := strings.TrimSpace(l[1])
|
||||
if err := validateLabelValue(key, value); err != nil {
|
||||
return labelsMap, err
|
||||
}
|
||||
labelsMap[key] = value
|
||||
}
|
||||
return labelsMap, nil
|
||||
}
|
||||
925
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go
generated
vendored
Normal file
925
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/labels/selector.go
generated
vendored
Normal file
@@ -0,0 +1,925 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/selector.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package labels
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"log"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation"
|
||||
)
|
||||
|
||||
// Requirements is AND of all requirements.
|
||||
type Requirements []Requirement
|
||||
|
||||
// Selector represents a label selector.
|
||||
type Selector interface {
|
||||
// Matches returns true if this selector matches the given set of labels.
|
||||
Matches(Labels) bool
|
||||
|
||||
// Empty returns true if this selector does not restrict the selection space.
|
||||
Empty() bool
|
||||
|
||||
// String returns a human readable string that represents this selector.
|
||||
String() string
|
||||
|
||||
// Add adds requirements to the Selector
|
||||
Add(r ...Requirement) Selector
|
||||
|
||||
// Requirements converts this interface into Requirements to expose
|
||||
// more detailed selection information.
|
||||
// If there are querying parameters, it will return converted requirements and selectable=true.
|
||||
// If this selector doesn't want to select anything, it will return selectable=false.
|
||||
Requirements() (requirements Requirements, selectable bool)
|
||||
|
||||
// Make a deep copy of the selector.
|
||||
DeepCopySelector() Selector
|
||||
|
||||
// RequiresExactMatch allows a caller to introspect whether a given selector
|
||||
// requires a single specific label to be set, and if so returns the value it
|
||||
// requires.
|
||||
RequiresExactMatch(label string) (value string, found bool)
|
||||
}
|
||||
|
||||
// Everything returns a selector that matches all labels.
|
||||
func Everything() Selector {
|
||||
return internalSelector{}
|
||||
}
|
||||
|
||||
type nothingSelector struct{}
|
||||
|
||||
func (n nothingSelector) Matches(_ Labels) bool { return false }
|
||||
func (n nothingSelector) Empty() bool { return false }
|
||||
func (n nothingSelector) String() string { return "" }
|
||||
func (n nothingSelector) Add(_ ...Requirement) Selector { return n }
|
||||
func (n nothingSelector) Requirements() (Requirements, bool) { return nil, false }
|
||||
func (n nothingSelector) DeepCopySelector() Selector { return n }
|
||||
func (n nothingSelector) RequiresExactMatch(label string) (value string, found bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Nothing returns a selector that matches no labels
|
||||
func Nothing() Selector {
|
||||
return nothingSelector{}
|
||||
}
|
||||
|
||||
// NewSelector returns a nil selector
|
||||
func NewSelector() Selector {
|
||||
return internalSelector(nil)
|
||||
}
|
||||
|
||||
type internalSelector []Requirement
|
||||
|
||||
func (s internalSelector) DeepCopy() internalSelector {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]Requirement, len(s))
|
||||
for i := range s {
|
||||
s[i].DeepCopyInto(&result[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s internalSelector) DeepCopySelector() Selector {
|
||||
return s.DeepCopy()
|
||||
}
|
||||
|
||||
// ByKey sorts requirements by key to obtain deterministic parser
|
||||
type ByKey []Requirement
|
||||
|
||||
func (a ByKey) Len() int { return len(a) }
|
||||
|
||||
func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key }
|
||||
|
||||
// Requirement contains values, a key, and an operator that relates the key and values.
|
||||
// The zero value of Requirement is invalid.
|
||||
// Requirement implements both set based match and exact match
|
||||
// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement.
|
||||
type Requirement struct {
|
||||
key string
|
||||
operator selection.Operator
|
||||
// In huge majority of cases we have at most one value here.
|
||||
// It is generally faster to operate on a single-element slice
|
||||
// than on a single-element map, so we have a slice here.
|
||||
strValues []string
|
||||
}
|
||||
|
||||
// NewRequirement is the constructor for a Requirement.
|
||||
// If any of these rules is violated, an error is returned:
|
||||
// (1) The operator can only be In, NotIn, Equals, DoubleEquals, NotEquals, Exists, or DoesNotExist.
|
||||
// (2) If the operator is In or NotIn, the values set must be non-empty.
|
||||
// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value.
|
||||
// (4) If the operator is Exists or DoesNotExist, the value set must be empty.
|
||||
// (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer.
|
||||
// (6) The key is invalid due to its length, or sequence
|
||||
// of characters. See validateLabelKey for more details.
|
||||
//
|
||||
// The empty string is a valid value in the input values set.
|
||||
func NewRequirement(key string, op selection.Operator, vals []string) (*Requirement, error) {
|
||||
if err := validateLabelKey(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch op {
|
||||
case selection.In, selection.NotIn:
|
||||
if len(vals) == 0 {
|
||||
return nil, fmt.Errorf("for 'in', 'notin' operators, values set can't be empty")
|
||||
}
|
||||
case selection.Equals, selection.DoubleEquals, selection.NotEquals:
|
||||
if len(vals) != 1 {
|
||||
return nil, fmt.Errorf("exact-match compatibility requires one single value")
|
||||
}
|
||||
case selection.Exists, selection.DoesNotExist:
|
||||
if len(vals) != 0 {
|
||||
return nil, fmt.Errorf("values set must be empty for exists and does not exist")
|
||||
}
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if len(vals) != 1 {
|
||||
return nil, fmt.Errorf("for 'Gt', 'Lt' operators, exactly one value is required")
|
||||
}
|
||||
for i := range vals {
|
||||
if _, err := strconv.ParseInt(vals[i], 10, 64); err != nil {
|
||||
return nil, fmt.Errorf("for 'Gt', 'Lt' operators, the value must be an integer")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("operator '%v' is not recognized", op)
|
||||
}
|
||||
|
||||
for i := range vals {
|
||||
if err := validateLabelValue(key, vals[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Requirement{key: key, operator: op, strValues: vals}, nil
|
||||
}
|
||||
|
||||
func (r *Requirement) hasValue(value string) bool {
|
||||
for i := range r.strValues {
|
||||
if r.strValues[i] == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Matches returns true if the Requirement matches the input Labels.
|
||||
// There is a match in the following cases:
|
||||
// (1) The operator is Exists and Labels has the Requirement's key.
|
||||
// (2) The operator is In, Labels has the Requirement's key and Labels'
|
||||
// value for that key is in Requirement's value set.
|
||||
// (3) The operator is NotIn, Labels has the Requirement's key and
|
||||
// Labels' value for that key is not in Requirement's value set.
|
||||
// (4) The operator is DoesNotExist or NotIn and Labels does not have the
|
||||
// Requirement's key.
|
||||
// (5) The operator is GreaterThanOperator or LessThanOperator, and Labels has
|
||||
// the Requirement's key and the corresponding value satisfies mathematical inequality.
|
||||
func (r *Requirement) Matches(ls Labels) bool {
|
||||
switch r.operator {
|
||||
case selection.In, selection.Equals, selection.DoubleEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
return r.hasValue(ls.Get(r.key))
|
||||
case selection.NotIn, selection.NotEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return true
|
||||
}
|
||||
return !r.hasValue(ls.Get(r.key))
|
||||
case selection.Exists:
|
||||
return ls.Has(r.key)
|
||||
case selection.DoesNotExist:
|
||||
return !ls.Has(r.key)
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
lsValue, err := strconv.ParseInt(ls.Get(r.key), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("ParseInt failed for value %+v in label %+v, %+v", ls.Get(r.key), ls, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// There should be only one strValue in r.strValues, and can be converted to an integer.
|
||||
if len(r.strValues) != 1 {
|
||||
log.Printf("Invalid values count %+v of requirement %#v, for 'Gt', 'Lt' operators, exactly one value is required", len(r.strValues), r)
|
||||
return false
|
||||
}
|
||||
|
||||
var rValue int64
|
||||
for i := range r.strValues {
|
||||
rValue, err = strconv.ParseInt(r.strValues[i], 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("ParseInt failed for value %+v in requirement %#v, for 'Gt', 'Lt' operators, the value must be an integer", r.strValues[i], r)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns requirement key
|
||||
func (r *Requirement) Key() string {
|
||||
return r.key
|
||||
}
|
||||
|
||||
// Operator returns requirement operator
|
||||
func (r *Requirement) Operator() selection.Operator {
|
||||
return r.operator
|
||||
}
|
||||
|
||||
// Values returns requirement values
|
||||
func (r *Requirement) Values() sets.String {
|
||||
ret := sets.String{}
|
||||
for i := range r.strValues {
|
||||
ret.Insert(r.strValues[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Empty returns true if the internalSelector doesn't restrict selection space
|
||||
func (lsel internalSelector) Empty() bool {
|
||||
if lsel == nil {
|
||||
return true
|
||||
}
|
||||
return len(lsel) == 0
|
||||
}
|
||||
|
||||
// String returns a human-readable string that represents this
|
||||
// Requirement. If called on an invalid Requirement, an error is
|
||||
// returned. See NewRequirement for creating a valid Requirement.
|
||||
func (r *Requirement) String() string {
|
||||
var buffer bytes.Buffer
|
||||
if r.operator == selection.DoesNotExist {
|
||||
buffer.WriteString("!")
|
||||
}
|
||||
buffer.WriteString(r.key)
|
||||
|
||||
switch r.operator {
|
||||
case selection.Equals:
|
||||
buffer.WriteString("=")
|
||||
case selection.DoubleEquals:
|
||||
buffer.WriteString("==")
|
||||
case selection.NotEquals:
|
||||
buffer.WriteString("!=")
|
||||
case selection.In:
|
||||
buffer.WriteString(" in ")
|
||||
case selection.NotIn:
|
||||
buffer.WriteString(" notin ")
|
||||
case selection.GreaterThan:
|
||||
buffer.WriteString(">")
|
||||
case selection.LessThan:
|
||||
buffer.WriteString("<")
|
||||
case selection.Exists, selection.DoesNotExist:
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
switch r.operator {
|
||||
case selection.In, selection.NotIn:
|
||||
buffer.WriteString("(")
|
||||
}
|
||||
if len(r.strValues) == 1 {
|
||||
buffer.WriteString(r.strValues[0])
|
||||
} else { // only > 1 since == 0 prohibited by NewRequirement
|
||||
// normalizes value order on output, without mutating the in-memory selector representation
|
||||
// also avoids normalization when it is not required, and ensures we do not mutate shared data
|
||||
buffer.WriteString(strings.Join(safeSort(r.strValues), ","))
|
||||
}
|
||||
|
||||
switch r.operator {
|
||||
case selection.In, selection.NotIn:
|
||||
buffer.WriteString(")")
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// safeSort sort input strings without modification
|
||||
func safeSort(in []string) []string {
|
||||
if sort.StringsAreSorted(in) {
|
||||
return in
|
||||
}
|
||||
out := make([]string, len(in))
|
||||
copy(out, in)
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Add adds requirements to the selector. It copies the current selector returning a new one
|
||||
func (lsel internalSelector) Add(reqs ...Requirement) Selector {
|
||||
var sel internalSelector
|
||||
for ix := range lsel {
|
||||
sel = append(sel, lsel[ix])
|
||||
}
|
||||
for _, r := range reqs {
|
||||
sel = append(sel, r)
|
||||
}
|
||||
sort.Sort(ByKey(sel))
|
||||
return sel
|
||||
}
|
||||
|
||||
// Matches for a internalSelector returns true if all
|
||||
// its Requirements match the input Labels. If any
|
||||
// Requirement does not match, false is returned.
|
||||
func (lsel internalSelector) Matches(l Labels) bool {
|
||||
for ix := range lsel {
|
||||
if matches := lsel[ix].Matches(l); !matches {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (lsel internalSelector) Requirements() (Requirements, bool) { return Requirements(lsel), true }
|
||||
|
||||
// String returns a comma-separated string of all
|
||||
// the internalSelector Requirements' human-readable strings.
|
||||
func (lsel internalSelector) String() string {
|
||||
var reqs []string
|
||||
for ix := range lsel {
|
||||
reqs = append(reqs, lsel[ix].String())
|
||||
}
|
||||
return strings.Join(reqs, ",")
|
||||
}
|
||||
|
||||
// RequiresExactMatch introspect whether a given selector requires a single specific field
|
||||
// to be set, and if so returns the value it requires.
|
||||
func (lsel internalSelector) RequiresExactMatch(label string) (value string, found bool) {
|
||||
for ix := range lsel {
|
||||
if lsel[ix].key == label {
|
||||
switch lsel[ix].operator {
|
||||
case selection.Equals, selection.DoubleEquals, selection.In:
|
||||
if len(lsel[ix].strValues) == 1 {
|
||||
return lsel[ix].strValues[0], true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Token represents constant definition for lexer token
|
||||
type Token int
|
||||
|
||||
const (
|
||||
// ErrorToken represents scan error
|
||||
ErrorToken Token = iota
|
||||
// EndOfStringToken represents end of string
|
||||
EndOfStringToken
|
||||
// ClosedParToken represents close parenthesis
|
||||
ClosedParToken
|
||||
// CommaToken represents the comma
|
||||
CommaToken
|
||||
// DoesNotExistToken represents logic not
|
||||
DoesNotExistToken
|
||||
// DoubleEqualsToken represents double equals
|
||||
DoubleEqualsToken
|
||||
// EqualsToken represents equal
|
||||
EqualsToken
|
||||
// GreaterThanToken represents greater than
|
||||
GreaterThanToken
|
||||
// IdentifierToken represents identifier, e.g. keys and values
|
||||
IdentifierToken
|
||||
// InToken represents in
|
||||
InToken
|
||||
// LessThanToken represents less than
|
||||
LessThanToken
|
||||
// NotEqualsToken represents not equal
|
||||
NotEqualsToken
|
||||
// NotInToken represents not in
|
||||
NotInToken
|
||||
// OpenParToken represents open parenthesis
|
||||
OpenParToken
|
||||
)
|
||||
|
||||
// string2token contains the mapping between lexer Token and token literal
|
||||
// (except IdentifierToken, EndOfStringToken and ErrorToken since it makes no sense)
|
||||
var string2token = map[string]Token{
|
||||
")": ClosedParToken,
|
||||
",": CommaToken,
|
||||
"!": DoesNotExistToken,
|
||||
"==": DoubleEqualsToken,
|
||||
"=": EqualsToken,
|
||||
">": GreaterThanToken,
|
||||
"in": InToken,
|
||||
"<": LessThanToken,
|
||||
"!=": NotEqualsToken,
|
||||
"notin": NotInToken,
|
||||
"(": OpenParToken,
|
||||
}
|
||||
|
||||
// ScannedItem contains the Token and the literal produced by the lexer.
|
||||
type ScannedItem struct {
|
||||
tok Token
|
||||
literal string
|
||||
}
|
||||
|
||||
// isWhitespace returns true if the rune is a space, tab, or newline.
|
||||
func isWhitespace(ch byte) bool {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
|
||||
}
|
||||
|
||||
// isSpecialSymbol detect if the character ch can be an operator
|
||||
func isSpecialSymbol(ch byte) bool {
|
||||
switch ch {
|
||||
case '=', '!', '(', ')', ',', '>', '<':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Lexer represents the Lexer struct for label selector.
|
||||
// It contains necessary informationt to tokenize the input string
|
||||
type Lexer struct {
|
||||
// s stores the string to be tokenized
|
||||
s string
|
||||
// pos is the position currently tokenized
|
||||
pos int
|
||||
}
|
||||
|
||||
// read return the character currently lexed
|
||||
// increment the position and check the buffer overflow
|
||||
func (l *Lexer) read() (b byte) {
|
||||
b = 0
|
||||
if l.pos < len(l.s) {
|
||||
b = l.s[l.pos]
|
||||
l.pos++
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// unread 'undoes' the last read character
|
||||
func (l *Lexer) unread() {
|
||||
l.pos--
|
||||
}
|
||||
|
||||
// scanIDOrKeyword scans string to recognize literal token (for example 'in') or an identifier.
|
||||
func (l *Lexer) scanIDOrKeyword() (tok Token, lit string) {
|
||||
var buffer []byte
|
||||
IdentifierLoop:
|
||||
for {
|
||||
switch ch := l.read(); {
|
||||
case ch == 0:
|
||||
break IdentifierLoop
|
||||
case isSpecialSymbol(ch) || isWhitespace(ch):
|
||||
l.unread()
|
||||
break IdentifierLoop
|
||||
default:
|
||||
buffer = append(buffer, ch)
|
||||
}
|
||||
}
|
||||
s := string(buffer)
|
||||
if val, ok := string2token[s]; ok { // is a literal token?
|
||||
return val, s
|
||||
}
|
||||
return IdentifierToken, s // otherwise is an identifier
|
||||
}
|
||||
|
||||
// scanSpecialSymbol scans string starting with special symbol.
|
||||
// special symbol identify non literal operators. "!=", "==", "="
|
||||
func (l *Lexer) scanSpecialSymbol() (Token, string) {
|
||||
lastScannedItem := ScannedItem{}
|
||||
var buffer []byte
|
||||
SpecialSymbolLoop:
|
||||
for {
|
||||
switch ch := l.read(); {
|
||||
case ch == 0:
|
||||
break SpecialSymbolLoop
|
||||
case isSpecialSymbol(ch):
|
||||
buffer = append(buffer, ch)
|
||||
if token, ok := string2token[string(buffer)]; ok {
|
||||
lastScannedItem = ScannedItem{tok: token, literal: string(buffer)}
|
||||
} else if lastScannedItem.tok != 0 {
|
||||
l.unread()
|
||||
break SpecialSymbolLoop
|
||||
}
|
||||
default:
|
||||
l.unread()
|
||||
break SpecialSymbolLoop
|
||||
}
|
||||
}
|
||||
if lastScannedItem.tok == 0 {
|
||||
return ErrorToken, fmt.Sprintf("error expected: keyword found '%s'", buffer)
|
||||
}
|
||||
return lastScannedItem.tok, lastScannedItem.literal
|
||||
}
|
||||
|
||||
// skipWhiteSpaces consumes all blank characters
|
||||
// returning the first non blank character
|
||||
func (l *Lexer) skipWhiteSpaces(ch byte) byte {
|
||||
for {
|
||||
if !isWhitespace(ch) {
|
||||
return ch
|
||||
}
|
||||
ch = l.read()
|
||||
}
|
||||
}
|
||||
|
||||
// Lex returns a pair of Token and the literal
|
||||
// literal is meaningfull only for IdentifierToken token
|
||||
func (l *Lexer) Lex() (tok Token, lit string) {
|
||||
switch ch := l.skipWhiteSpaces(l.read()); {
|
||||
case ch == 0:
|
||||
return EndOfStringToken, ""
|
||||
case isSpecialSymbol(ch):
|
||||
l.unread()
|
||||
return l.scanSpecialSymbol()
|
||||
default:
|
||||
l.unread()
|
||||
return l.scanIDOrKeyword()
|
||||
}
|
||||
}
|
||||
|
||||
// Parser data structure contains the label selector parser data structure
|
||||
type Parser struct {
|
||||
l *Lexer
|
||||
scannedItems []ScannedItem
|
||||
position int
|
||||
}
|
||||
|
||||
// ParserContext represents context during parsing:
|
||||
// some literal for example 'in' and 'notin' can be
|
||||
// recognized as operator for example 'x in (a)' but
|
||||
// it can be recognized as value for example 'value in (in)'
|
||||
type ParserContext int
|
||||
|
||||
const (
|
||||
// KeyAndOperator represents key and operator
|
||||
KeyAndOperator ParserContext = iota
|
||||
// Values represents values
|
||||
Values
|
||||
)
|
||||
|
||||
// lookahead func returns the current token and string. No increment of current position
|
||||
func (p *Parser) lookahead(context ParserContext) (Token, string) {
|
||||
tok, lit := p.scannedItems[p.position].tok, p.scannedItems[p.position].literal
|
||||
if context == Values {
|
||||
switch tok {
|
||||
case InToken, NotInToken:
|
||||
tok = IdentifierToken
|
||||
}
|
||||
}
|
||||
return tok, lit
|
||||
}
|
||||
|
||||
// consume returns current token and string. Increments the position
|
||||
func (p *Parser) consume(context ParserContext) (Token, string) {
|
||||
p.position++
|
||||
tok, lit := p.scannedItems[p.position-1].tok, p.scannedItems[p.position-1].literal
|
||||
if context == Values {
|
||||
switch tok {
|
||||
case InToken, NotInToken:
|
||||
tok = IdentifierToken
|
||||
}
|
||||
}
|
||||
return tok, lit
|
||||
}
|
||||
|
||||
// scan runs through the input string and stores the ScannedItem in an array
|
||||
// Parser can now lookahead and consume the tokens
|
||||
func (p *Parser) scan() {
|
||||
for {
|
||||
token, literal := p.l.Lex()
|
||||
p.scannedItems = append(p.scannedItems, ScannedItem{token, literal})
|
||||
if token == EndOfStringToken {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse runs the left recursive descending algorithm
|
||||
// on input string. It returns a list of Requirement objects.
|
||||
func (p *Parser) parse() (internalSelector, error) {
|
||||
p.scan() // init scannedItems
|
||||
|
||||
var requirements internalSelector
|
||||
for {
|
||||
tok, lit := p.lookahead(Values)
|
||||
switch tok {
|
||||
case IdentifierToken, DoesNotExistToken:
|
||||
r, err := p.parseRequirement()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse requirement: %v", err)
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
t, l := p.consume(Values)
|
||||
switch t {
|
||||
case EndOfStringToken:
|
||||
return requirements, nil
|
||||
case CommaToken:
|
||||
t2, l2 := p.lookahead(Values)
|
||||
if t2 != IdentifierToken && t2 != DoesNotExistToken {
|
||||
return nil, fmt.Errorf("found '%s', expected: identifier after ','", l2)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',' or 'end of string'", l)
|
||||
}
|
||||
case EndOfStringToken:
|
||||
return requirements, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: !, identifier, or 'end of string'", lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) parseRequirement() (*Requirement, error) {
|
||||
key, operator, err := p.parseKeyAndInferOperator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if operator == selection.Exists || operator == selection.DoesNotExist { // operator found lookahead set checked
|
||||
return NewRequirement(key, operator, []string{})
|
||||
}
|
||||
operator, err = p.parseOperator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var values sets.String
|
||||
switch operator {
|
||||
case selection.In, selection.NotIn:
|
||||
values, err = p.parseValues()
|
||||
case selection.Equals, selection.DoubleEquals, selection.NotEquals, selection.GreaterThan, selection.LessThan:
|
||||
values, err = p.parseExactValue()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewRequirement(key, operator, values.List())
|
||||
|
||||
}
|
||||
|
||||
// parseKeyAndInferOperator parse literals.
|
||||
// in case of no operator '!, in, notin, ==, =, !=' are found
|
||||
// the 'exists' operator is inferred
|
||||
func (p *Parser) parseKeyAndInferOperator() (string, selection.Operator, error) {
|
||||
var operator selection.Operator
|
||||
tok, literal := p.consume(Values)
|
||||
if tok == DoesNotExistToken {
|
||||
operator = selection.DoesNotExist
|
||||
tok, literal = p.consume(Values)
|
||||
}
|
||||
if tok != IdentifierToken {
|
||||
err := fmt.Errorf("found '%s', expected: identifier", literal)
|
||||
return "", "", err
|
||||
}
|
||||
if err := validateLabelKey(literal); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if t, _ := p.lookahead(Values); t == EndOfStringToken || t == CommaToken {
|
||||
if operator != selection.DoesNotExist {
|
||||
operator = selection.Exists
|
||||
}
|
||||
}
|
||||
return literal, operator, nil
|
||||
}
|
||||
|
||||
// parseOperator return operator and eventually matchType
|
||||
// matchType can be exact
|
||||
func (p *Parser) parseOperator() (op selection.Operator, err error) {
|
||||
tok, lit := p.consume(KeyAndOperator)
|
||||
switch tok {
|
||||
// DoesNotExistToken shouldn't be here because it's a unary operator, not a binary operator
|
||||
case InToken:
|
||||
op = selection.In
|
||||
case EqualsToken:
|
||||
op = selection.Equals
|
||||
case DoubleEqualsToken:
|
||||
op = selection.DoubleEquals
|
||||
case GreaterThanToken:
|
||||
op = selection.GreaterThan
|
||||
case LessThanToken:
|
||||
op = selection.LessThan
|
||||
case NotInToken:
|
||||
op = selection.NotIn
|
||||
case NotEqualsToken:
|
||||
op = selection.NotEquals
|
||||
default:
|
||||
return "", fmt.Errorf("found '%s', expected: '=', '!=', '==', 'in', notin'", lit)
|
||||
}
|
||||
return op, nil
|
||||
}
|
||||
|
||||
// parseValues parses the values for set based matching (x,y,z)
|
||||
func (p *Parser) parseValues() (sets.String, error) {
|
||||
tok, lit := p.consume(Values)
|
||||
if tok != OpenParToken {
|
||||
return nil, fmt.Errorf("found '%s' expected: '('", lit)
|
||||
}
|
||||
tok, lit = p.lookahead(Values)
|
||||
switch tok {
|
||||
case IdentifierToken, CommaToken:
|
||||
s, err := p.parseIdentifiersList() // handles general cases
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
if tok, _ = p.consume(Values); tok != ClosedParToken {
|
||||
return nil, fmt.Errorf("found '%s', expected: ')'", lit)
|
||||
}
|
||||
return s, nil
|
||||
case ClosedParToken: // handles "()"
|
||||
p.consume(Values)
|
||||
return sets.NewString(""), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',', ')' or identifier", lit)
|
||||
}
|
||||
}
|
||||
|
||||
// parseIdentifiersList parses a (possibly empty) list of
|
||||
// of comma separated (possibly empty) identifiers
|
||||
func (p *Parser) parseIdentifiersList() (sets.String, error) {
|
||||
s := sets.NewString()
|
||||
for {
|
||||
tok, lit := p.consume(Values)
|
||||
switch tok {
|
||||
case IdentifierToken:
|
||||
s.Insert(lit)
|
||||
tok2, lit2 := p.lookahead(Values)
|
||||
switch tok2 {
|
||||
case CommaToken:
|
||||
continue
|
||||
case ClosedParToken:
|
||||
return s, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found '%s', expected: ',' or ')'", lit2)
|
||||
}
|
||||
case CommaToken: // handled here since we can have "(,"
|
||||
if s.Len() == 0 {
|
||||
s.Insert("") // to handle (,
|
||||
}
|
||||
tok2, _ := p.lookahead(Values)
|
||||
if tok2 == ClosedParToken {
|
||||
s.Insert("") // to handle ,) Double "" removed by StringSet
|
||||
return s, nil
|
||||
}
|
||||
if tok2 == CommaToken {
|
||||
p.consume(Values)
|
||||
s.Insert("") // to handle ,, Double "" removed by StringSet
|
||||
}
|
||||
default: // it can be operator
|
||||
return s, fmt.Errorf("found '%s', expected: ',', or identifier", lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseExactValue parses the only value for exact match style
|
||||
func (p *Parser) parseExactValue() (sets.String, error) {
|
||||
s := sets.NewString()
|
||||
tok, lit := p.lookahead(Values)
|
||||
if tok == EndOfStringToken || tok == CommaToken {
|
||||
s.Insert("")
|
||||
return s, nil
|
||||
}
|
||||
tok, lit = p.consume(Values)
|
||||
if tok == IdentifierToken {
|
||||
s.Insert(lit)
|
||||
return s, nil
|
||||
}
|
||||
return nil, fmt.Errorf("found '%s', expected: identifier", lit)
|
||||
}
|
||||
|
||||
// Parse takes a string representing a selector and returns a selector
|
||||
// object, or an error. This parsing function differs from ParseSelector
|
||||
// as they parse different selectors with different syntaxes.
|
||||
// The input will cause an error if it does not follow this form:
|
||||
//
|
||||
// <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax>
|
||||
// <requirement> ::= [!] KEY [ <set-based-restriction> | <exact-match-restriction> ]
|
||||
// <set-based-restriction> ::= "" | <inclusion-exclusion> <value-set>
|
||||
// <inclusion-exclusion> ::= <inclusion> | <exclusion>
|
||||
// <exclusion> ::= "notin"
|
||||
// <inclusion> ::= "in"
|
||||
// <value-set> ::= "(" <values> ")"
|
||||
// <values> ::= VALUE | VALUE "," <values>
|
||||
// <exact-match-restriction> ::= ["="|"=="|"!="] VALUE
|
||||
//
|
||||
// KEY is a sequence of one or more characters following [ DNS_SUBDOMAIN "/" ] DNS_LABEL. Max length is 63 characters.
|
||||
// VALUE is a sequence of zero or more characters "([A-Za-z0-9_-\.])". Max length is 63 characters.
|
||||
// Delimiter is white space: (' ', '\t')
|
||||
// Example of valid syntax:
|
||||
// "x in (foo,,baz),y,z notin ()"
|
||||
//
|
||||
// Note:
|
||||
// (1) Inclusion - " in " - denotes that the KEY exists and is equal to any of the
|
||||
// VALUEs in its requirement
|
||||
// (2) Exclusion - " notin " - denotes that the KEY is not equal to any
|
||||
// of the VALUEs in its requirement or does not exist
|
||||
// (3) The empty string is a valid VALUE
|
||||
// (4) A requirement with just a KEY - as in "y" above - denotes that
|
||||
// the KEY exists and can be any VALUE.
|
||||
// (5) A requirement with just !KEY requires that the KEY not exist.
|
||||
//
|
||||
func Parse(selector string) (Selector, error) {
|
||||
parsedSelector, err := parse(selector)
|
||||
if err == nil {
|
||||
return parsedSelector, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse parses the string representation of the selector and returns the internalSelector struct.
|
||||
// The callers of this method can then decide how to return the internalSelector struct to their
|
||||
// callers. This function has two callers now, one returns a Selector interface and the other
|
||||
// returns a list of requirements.
|
||||
func parse(selector string) (internalSelector, error) {
|
||||
p := &Parser{l: &Lexer{s: selector, pos: 0}}
|
||||
items, err := p.parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Sort(ByKey(items)) // sort to grant determistic parsing
|
||||
return internalSelector(items), err
|
||||
}
|
||||
|
||||
func validateLabelKey(k string) error {
|
||||
if errs := validation.IsQualifiedName(k); len(errs) != 0 {
|
||||
return fmt.Errorf("invalid label key %q: %s", k, strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateLabelValue(k, v string) error {
|
||||
if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
|
||||
return fmt.Errorf("invalid label value: %q: at key: %q: %s", v, k, strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectorFromSet returns a Selector which will match exactly the given Set. A
|
||||
// nil and empty Sets are considered equivalent to Everything().
|
||||
// It does not perform any validation, which means the server will reject
|
||||
// the request if the Set contains invalid values.
|
||||
func SelectorFromSet(ls Set) Selector {
|
||||
return SelectorFromValidatedSet(ls)
|
||||
}
|
||||
|
||||
// ValidatedSelectorFromSet returns a Selector which will match exactly the given Set. A
|
||||
// nil and empty Sets are considered equivalent to Everything().
|
||||
// The Set is validated client-side, which allows to catch errors early.
|
||||
func ValidatedSelectorFromSet(ls Set) (Selector, error) {
|
||||
if ls == nil || len(ls) == 0 {
|
||||
return internalSelector{}, nil
|
||||
}
|
||||
requirements := make([]Requirement, 0, len(ls))
|
||||
for label, value := range ls {
|
||||
r, err := NewRequirement(label, selection.Equals, []string{value})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
}
|
||||
// sort to have deterministic string representation
|
||||
sort.Sort(ByKey(requirements))
|
||||
return internalSelector(requirements), nil
|
||||
}
|
||||
|
||||
// SelectorFromValidatedSet returns a Selector which will match exactly the given Set.
|
||||
// A nil and empty Sets are considered equivalent to Everything().
|
||||
// It assumes that Set is already validated and doesn't do any validation.
|
||||
func SelectorFromValidatedSet(ls Set) Selector {
|
||||
if ls == nil || len(ls) == 0 {
|
||||
return internalSelector{}
|
||||
}
|
||||
requirements := make([]Requirement, 0, len(ls))
|
||||
for label, value := range ls {
|
||||
requirements = append(requirements, Requirement{key: label, operator: selection.Equals, strValues: []string{value}})
|
||||
}
|
||||
// sort to have deterministic string representation
|
||||
sort.Sort(ByKey(requirements))
|
||||
return internalSelector(requirements)
|
||||
}
|
||||
|
||||
// ParseToRequirements takes a string representing a selector and returns a list of
|
||||
// requirements. This function is suitable for those callers that perform additional
|
||||
// processing on selector requirements.
|
||||
// See the documentation for Parse() function for more details.
|
||||
// TODO: Consider exporting the internalSelector type instead.
|
||||
func ParseToRequirements(selector string) ([]Requirement, error) {
|
||||
return parse(selector)
|
||||
}
|
||||
36
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection/operator.go
generated
vendored
Normal file
36
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/selection/operator.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/selection/operator.go
|
||||
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package selection
|
||||
|
||||
// Operator represents a key/field's relationship to value(s).
|
||||
// See labels.Requirement and fields.Requirement for more details.
|
||||
type Operator string
|
||||
|
||||
const (
|
||||
DoesNotExist Operator = "!"
|
||||
Equals Operator = "="
|
||||
DoubleEquals Operator = "=="
|
||||
In Operator = "in"
|
||||
NotEquals Operator = "!="
|
||||
NotIn Operator = "notin"
|
||||
Exists Operator = "exists"
|
||||
GreaterThan Operator = "gt"
|
||||
LessThan Operator = "lt"
|
||||
)
|
||||
252
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors/errors.go
generated
vendored
Normal file
252
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/errors/errors.go
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
)
|
||||
|
||||
// MessageCountMap contains occurrence for each error message.
|
||||
type MessageCountMap map[string]int
|
||||
|
||||
// Aggregate represents an object that contains multiple errors, but does not
|
||||
// necessarily have singular semantic meaning.
|
||||
// The aggregate can be used with `errors.Is()` to check for the occurrence of
|
||||
// a specific error type.
|
||||
// Errors.As() is not supported, because the caller presumably cares about a
|
||||
// specific error of potentially multiple that match the given type.
|
||||
type Aggregate interface {
|
||||
error
|
||||
Errors() []error
|
||||
Is(error) bool
|
||||
}
|
||||
|
||||
// NewAggregate converts a slice of errors into an Aggregate interface, which
|
||||
// is itself an implementation of the error interface. If the slice is empty,
|
||||
// this returns nil.
|
||||
// It will check if any of the element of input error list is nil, to avoid
|
||||
// nil pointer panic when call Error().
|
||||
func NewAggregate(errlist []error) Aggregate {
|
||||
if len(errlist) == 0 {
|
||||
return nil
|
||||
}
|
||||
// In case of input error list contains nil
|
||||
var errs []error
|
||||
for _, e := range errlist {
|
||||
if e != nil {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return aggregate(errs)
|
||||
}
|
||||
|
||||
// This helper implements the error and Errors interfaces. Keeping it private
|
||||
// prevents people from making an aggregate of 0 errors, which is not
|
||||
// an error, but does satisfy the error interface.
|
||||
type aggregate []error
|
||||
|
||||
// Error is part of the error interface.
|
||||
func (agg aggregate) Error() string {
|
||||
if len(agg) == 0 {
|
||||
// This should never happen, really.
|
||||
return ""
|
||||
}
|
||||
if len(agg) == 1 {
|
||||
return agg[0].Error()
|
||||
}
|
||||
seenerrs := sets.NewString()
|
||||
result := ""
|
||||
agg.visit(func(err error) bool {
|
||||
msg := err.Error()
|
||||
if seenerrs.Has(msg) {
|
||||
return false
|
||||
}
|
||||
seenerrs.Insert(msg)
|
||||
if len(seenerrs) > 1 {
|
||||
result += ", "
|
||||
}
|
||||
result += msg
|
||||
return false
|
||||
})
|
||||
if len(seenerrs) == 1 {
|
||||
return result
|
||||
}
|
||||
return "[" + result + "]"
|
||||
}
|
||||
|
||||
func (agg aggregate) Is(target error) bool {
|
||||
return agg.visit(func(err error) bool {
|
||||
return errors.Is(err, target)
|
||||
})
|
||||
}
|
||||
|
||||
func (agg aggregate) visit(f func(err error) bool) bool {
|
||||
for _, err := range agg {
|
||||
switch err := err.(type) {
|
||||
case aggregate:
|
||||
if match := err.visit(f); match {
|
||||
return match
|
||||
}
|
||||
case Aggregate:
|
||||
for _, nestedErr := range err.Errors() {
|
||||
if match := f(nestedErr); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
default:
|
||||
if match := f(err); match {
|
||||
return match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Errors is part of the Aggregate interface.
|
||||
func (agg aggregate) Errors() []error {
|
||||
return []error(agg)
|
||||
}
|
||||
|
||||
// Matcher is used to match errors. Returns true if the error matches.
|
||||
type Matcher func(error) bool
|
||||
|
||||
// FilterOut removes all errors that match any of the matchers from the input
|
||||
// error. If the input is a singular error, only that error is tested. If the
|
||||
// input implements the Aggregate interface, the list of errors will be
|
||||
// processed recursively.
|
||||
//
|
||||
// This can be used, for example, to remove known-OK errors (such as io.EOF or
|
||||
// os.PathNotFound) from a list of errors.
|
||||
func FilterOut(err error, fns ...Matcher) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if agg, ok := err.(Aggregate); ok {
|
||||
return NewAggregate(filterErrors(agg.Errors(), fns...))
|
||||
}
|
||||
if !matchesError(err, fns...) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// matchesError returns true if any Matcher returns true
|
||||
func matchesError(err error, fns ...Matcher) bool {
|
||||
for _, fn := range fns {
|
||||
if fn(err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// filterErrors returns any errors (or nested errors, if the list contains
|
||||
// nested Errors) for which all fns return false. If no errors
|
||||
// remain a nil list is returned. The resulting silec will have all
|
||||
// nested slices flattened as a side effect.
|
||||
func filterErrors(list []error, fns ...Matcher) []error {
|
||||
result := []error{}
|
||||
for _, err := range list {
|
||||
r := FilterOut(err, fns...)
|
||||
if r != nil {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Flatten takes an Aggregate, which may hold other Aggregates in arbitrary
|
||||
// nesting, and flattens them all into a single Aggregate, recursively.
|
||||
func Flatten(agg Aggregate) Aggregate {
|
||||
result := []error{}
|
||||
if agg == nil {
|
||||
return nil
|
||||
}
|
||||
for _, err := range agg.Errors() {
|
||||
if a, ok := err.(Aggregate); ok {
|
||||
r := Flatten(a)
|
||||
if r != nil {
|
||||
result = append(result, r.Errors()...)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
result = append(result, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return NewAggregate(result)
|
||||
}
|
||||
|
||||
// CreateAggregateFromMessageCountMap converts MessageCountMap Aggregate
|
||||
func CreateAggregateFromMessageCountMap(m MessageCountMap) Aggregate {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]error, 0, len(m))
|
||||
for errStr, count := range m {
|
||||
var countStr string
|
||||
if count > 1 {
|
||||
countStr = fmt.Sprintf(" (repeated %v times)", count)
|
||||
}
|
||||
result = append(result, fmt.Errorf("%v%v", errStr, countStr))
|
||||
}
|
||||
return NewAggregate(result)
|
||||
}
|
||||
|
||||
// Reduce will return err or, if err is an Aggregate and only has one item,
|
||||
// the first item in the aggregate.
|
||||
func Reduce(err error) error {
|
||||
if agg, ok := err.(Aggregate); ok && err != nil {
|
||||
switch len(agg.Errors()) {
|
||||
case 1:
|
||||
return agg.Errors()[0]
|
||||
case 0:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AggregateGoroutines runs the provided functions in parallel, stuffing all
|
||||
// non-nil errors into the returned Aggregate.
|
||||
// Returns nil if all the functions complete successfully.
|
||||
func AggregateGoroutines(funcs ...func() error) Aggregate {
|
||||
errChan := make(chan error, len(funcs))
|
||||
for _, f := range funcs {
|
||||
go func(f func() error) { errChan <- f() }(f)
|
||||
}
|
||||
errs := make([]error, 0)
|
||||
for i := 0; i < cap(errChan); i++ {
|
||||
if err := <-errChan; err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return NewAggregate(errs)
|
||||
}
|
||||
|
||||
// ErrPreconditionViolated is returned when the precondition is violated
|
||||
var ErrPreconditionViolated = errors.New("precondition is violated")
|
||||
24
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/empty.go
generated
vendored
Normal file
24
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/empty.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/sets/empty.go
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
||||
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/string.go
generated
vendored
Normal file
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets/string.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/sets/string.go
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) String {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) String {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
||||
275
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/errors.go
generated
vendored
Normal file
275
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/errors.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/field/errors.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
utilerrors "sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Error is an implementation of the 'error' interface, which represents a
|
||||
// field-level validation error.
|
||||
type Error struct {
|
||||
Type ErrorType
|
||||
Field string
|
||||
BadValue interface{}
|
||||
Detail string
|
||||
}
|
||||
|
||||
var _ error = &Error{}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (v *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody())
|
||||
}
|
||||
|
||||
// ErrorBody returns the error message without the field name. This is useful
|
||||
// for building nice-looking higher-level error reporting.
|
||||
func (v *Error) ErrorBody() string {
|
||||
var s string
|
||||
switch v.Type {
|
||||
case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
|
||||
s = v.Type.String()
|
||||
default:
|
||||
value := v.BadValue
|
||||
valueType := reflect.TypeOf(value)
|
||||
if value == nil || valueType == nil {
|
||||
value = "null"
|
||||
} else if valueType.Kind() == reflect.Ptr {
|
||||
if reflectValue := reflect.ValueOf(value); reflectValue.IsNil() {
|
||||
value = "null"
|
||||
} else {
|
||||
value = reflectValue.Elem().Interface()
|
||||
}
|
||||
}
|
||||
switch t := value.(type) {
|
||||
case int64, int32, float64, float32, bool:
|
||||
// use simple printer for simple types
|
||||
s = fmt.Sprintf("%s: %v", v.Type, value)
|
||||
case string:
|
||||
s = fmt.Sprintf("%s: %q", v.Type, t)
|
||||
case fmt.Stringer:
|
||||
// anything that defines String() is better than raw struct
|
||||
s = fmt.Sprintf("%s: %s", v.Type, t.String())
|
||||
default:
|
||||
// fallback to raw struct
|
||||
// TODO: internal types have panic guards against json.Marshalling to prevent
|
||||
// accidental use of internal types in external serialized form. For now, use
|
||||
// %#v, although it would be better to show a more expressive output in the future
|
||||
s = fmt.Sprintf("%s: %#v", v.Type, value)
|
||||
}
|
||||
}
|
||||
if len(v.Detail) != 0 {
|
||||
s += fmt.Sprintf(": %s", v.Detail)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ErrorType is a machine readable value providing more detail about why
|
||||
// a field is invalid. These values are expected to match 1-1 with
|
||||
// CauseType in api/types.go.
|
||||
type ErrorType string
|
||||
|
||||
// TODO: These values are duplicated in api/types.go, but there's a circular dep. Fix it.
|
||||
const (
|
||||
// ErrorTypeNotFound is used to report failure to find a requested value
|
||||
// (e.g. looking up an ID). See NotFound().
|
||||
ErrorTypeNotFound ErrorType = "FieldValueNotFound"
|
||||
// ErrorTypeRequired is used to report required values that are not
|
||||
// provided (e.g. empty strings, null values, or empty arrays). See
|
||||
// Required().
|
||||
ErrorTypeRequired ErrorType = "FieldValueRequired"
|
||||
// ErrorTypeDuplicate is used to report collisions of values that must be
|
||||
// unique (e.g. unique IDs). See Duplicate().
|
||||
ErrorTypeDuplicate ErrorType = "FieldValueDuplicate"
|
||||
// ErrorTypeInvalid is used to report malformed values (e.g. failed regex
|
||||
// match, too long, out of bounds). See Invalid().
|
||||
ErrorTypeInvalid ErrorType = "FieldValueInvalid"
|
||||
// ErrorTypeNotSupported is used to report unknown values for enumerated
|
||||
// fields (e.g. a list of valid values). See NotSupported().
|
||||
ErrorTypeNotSupported ErrorType = "FieldValueNotSupported"
|
||||
// ErrorTypeForbidden is used to report valid (as per formatting rules)
|
||||
// values which would be accepted under some conditions, but which are not
|
||||
// permitted by the current conditions (such as security policy). See
|
||||
// Forbidden().
|
||||
ErrorTypeForbidden ErrorType = "FieldValueForbidden"
|
||||
// ErrorTypeTooLong is used to report that the given value is too long.
|
||||
// This is similar to ErrorTypeInvalid, but the error will not include the
|
||||
// too-long value. See TooLong().
|
||||
ErrorTypeTooLong ErrorType = "FieldValueTooLong"
|
||||
// ErrorTypeTooMany is used to report "too many". This is used to
|
||||
// report that a given list has too many items. This is similar to FieldValueTooLong,
|
||||
// but the error indicates quantity instead of length.
|
||||
ErrorTypeTooMany ErrorType = "FieldValueTooMany"
|
||||
// ErrorTypeInternal is used to report other errors that are not related
|
||||
// to user input. See InternalError().
|
||||
ErrorTypeInternal ErrorType = "InternalError"
|
||||
)
|
||||
|
||||
// String converts a ErrorType into its corresponding canonical error message.
|
||||
func (t ErrorType) String() string {
|
||||
switch t {
|
||||
case ErrorTypeNotFound:
|
||||
return "Not found"
|
||||
case ErrorTypeRequired:
|
||||
return "Required value"
|
||||
case ErrorTypeDuplicate:
|
||||
return "Duplicate value"
|
||||
case ErrorTypeInvalid:
|
||||
return "Invalid value"
|
||||
case ErrorTypeNotSupported:
|
||||
return "Unsupported value"
|
||||
case ErrorTypeForbidden:
|
||||
return "Forbidden"
|
||||
case ErrorTypeTooLong:
|
||||
return "Too long"
|
||||
case ErrorTypeTooMany:
|
||||
return "Too many"
|
||||
case ErrorTypeInternal:
|
||||
return "Internal error"
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized validation error: %q", string(t)))
|
||||
}
|
||||
}
|
||||
|
||||
// NotFound returns a *Error indicating "value not found". This is
|
||||
// used to report failure to find a requested value (e.g. looking up an ID).
|
||||
func NotFound(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeNotFound, field.String(), value, ""}
|
||||
}
|
||||
|
||||
// Required returns a *Error indicating "value required". This is used
|
||||
// to report required values that are not provided (e.g. empty strings, null
|
||||
// values, or empty arrays).
|
||||
func Required(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeRequired, field.String(), "", detail}
|
||||
}
|
||||
|
||||
// Duplicate returns a *Error indicating "duplicate value". This is
|
||||
// used to report collisions of values that must be unique (e.g. names or IDs).
|
||||
func Duplicate(field *Path, value interface{}) *Error {
|
||||
return &Error{ErrorTypeDuplicate, field.String(), value, ""}
|
||||
}
|
||||
|
||||
// Invalid returns a *Error indicating "invalid value". This is used
|
||||
// to report malformed values (e.g. failed regex match, too long, out of bounds).
|
||||
func Invalid(field *Path, value interface{}, detail string) *Error {
|
||||
return &Error{ErrorTypeInvalid, field.String(), value, detail}
|
||||
}
|
||||
|
||||
// NotSupported returns a *Error indicating "unsupported value".
|
||||
// This is used to report unknown values for enumerated fields (e.g. a list of
|
||||
// valid values).
|
||||
func NotSupported(field *Path, value interface{}, validValues []string) *Error {
|
||||
detail := ""
|
||||
if validValues != nil && len(validValues) > 0 {
|
||||
quotedValues := make([]string, len(validValues))
|
||||
for i, v := range validValues {
|
||||
quotedValues[i] = strconv.Quote(v)
|
||||
}
|
||||
detail = "supported values: " + strings.Join(quotedValues, ", ")
|
||||
}
|
||||
return &Error{ErrorTypeNotSupported, field.String(), value, detail}
|
||||
}
|
||||
|
||||
// Forbidden returns a *Error indicating "forbidden". This is used to
|
||||
// report valid (as per formatting rules) values which would be accepted under
|
||||
// some conditions, but which are not permitted by current conditions (e.g.
|
||||
// security policy).
|
||||
func Forbidden(field *Path, detail string) *Error {
|
||||
return &Error{ErrorTypeForbidden, field.String(), "", detail}
|
||||
}
|
||||
|
||||
// TooLong returns a *Error indicating "too long". This is used to
|
||||
// report that the given value is too long. This is similar to
|
||||
// Invalid, but the returned error will not include the too-long
|
||||
// value.
|
||||
func TooLong(field *Path, value interface{}, maxLength int) *Error {
|
||||
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d bytes", maxLength)}
|
||||
}
|
||||
|
||||
// TooMany returns a *Error indicating "too many". This is used to
|
||||
// report that a given list has too many items. This is similar to TooLong,
|
||||
// but the returned error indicates quantity instead of length.
|
||||
func TooMany(field *Path, actualQuantity, maxQuantity int) *Error {
|
||||
return &Error{ErrorTypeTooMany, field.String(), actualQuantity, fmt.Sprintf("must have at most %d items", maxQuantity)}
|
||||
}
|
||||
|
||||
// InternalError returns a *Error indicating "internal error". This is used
|
||||
// to signal that an error was found that was not directly related to user
|
||||
// input. The err argument must be non-nil.
|
||||
func InternalError(field *Path, err error) *Error {
|
||||
return &Error{ErrorTypeInternal, field.String(), nil, err.Error()}
|
||||
}
|
||||
|
||||
// ErrorList holds a set of Errors. It is plausible that we might one day have
|
||||
// non-field errors in this same umbrella package, but for now we don't, so
|
||||
// we can keep it simple and leave ErrorList here.
|
||||
type ErrorList []*Error
|
||||
|
||||
// NewErrorTypeMatcher returns an errors.Matcher that returns true
|
||||
// if the provided error is a Error and has the provided ErrorType.
|
||||
func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher {
|
||||
return func(err error) bool {
|
||||
if e, ok := err.(*Error); ok {
|
||||
return e.Type == t
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ToAggregate converts the ErrorList into an errors.Aggregate.
|
||||
func (list ErrorList) ToAggregate() utilerrors.Aggregate {
|
||||
errs := make([]error, 0, len(list))
|
||||
errorMsgs := sets.NewString()
|
||||
for _, err := range list {
|
||||
msg := fmt.Sprintf("%v", err)
|
||||
if errorMsgs.Has(msg) {
|
||||
continue
|
||||
}
|
||||
errorMsgs.Insert(msg)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func fromAggregate(agg utilerrors.Aggregate) ErrorList {
|
||||
errs := agg.Errors()
|
||||
list := make(ErrorList, len(errs))
|
||||
for i := range errs {
|
||||
list[i] = errs[i].(*Error)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Filter removes items from the ErrorList that match the provided fns.
|
||||
func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList {
|
||||
err := utilerrors.FilterOut(list.ToAggregate(), fns...)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// FilterOut takes an Aggregate and returns an Aggregate
|
||||
return fromAggregate(err.(utilerrors.Aggregate))
|
||||
}
|
||||
94
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/path.go
generated
vendored
Normal file
94
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field/path.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/field/path.go
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Path represents the path from some root to a particular field.
|
||||
type Path struct {
|
||||
name string // the name of this field or "" if this is an index
|
||||
index string // if name == "", this is a subscript (index or map key) of the previous element
|
||||
parent *Path // nil if this is the root element
|
||||
}
|
||||
|
||||
// NewPath creates a root Path object.
|
||||
func NewPath(name string, moreNames ...string) *Path {
|
||||
r := &Path{name: name, parent: nil}
|
||||
for _, anotherName := range moreNames {
|
||||
r = &Path{name: anotherName, parent: r}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Root returns the root element of this Path.
|
||||
func (p *Path) Root() *Path {
|
||||
for ; p.parent != nil; p = p.parent {
|
||||
// Do nothing.
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Child creates a new Path that is a child of the method receiver.
|
||||
func (p *Path) Child(name string, moreNames ...string) *Path {
|
||||
r := NewPath(name, moreNames...)
|
||||
r.Root().parent = p
|
||||
return r
|
||||
}
|
||||
|
||||
// Index indicates that the previous Path is to be subscripted by an int.
|
||||
// This sets the same underlying value as Key.
|
||||
func (p *Path) Index(index int) *Path {
|
||||
return &Path{index: strconv.Itoa(index), parent: p}
|
||||
}
|
||||
|
||||
// Key indicates that the previous Path is to be subscripted by a string.
|
||||
// This sets the same underlying value as Index.
|
||||
func (p *Path) Key(key string) *Path {
|
||||
return &Path{index: key, parent: p}
|
||||
}
|
||||
|
||||
// String produces a string representation of the Path.
|
||||
func (p *Path) String() string {
|
||||
// make a slice to iterate
|
||||
elems := []*Path{}
|
||||
for ; p != nil; p = p.parent {
|
||||
elems = append(elems, p)
|
||||
}
|
||||
|
||||
// iterate, but it has to be backwards
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i := range elems {
|
||||
p := elems[len(elems)-1-i]
|
||||
if p.parent != nil && len(p.name) > 0 {
|
||||
// This is either the root or it is a subscript.
|
||||
buf.WriteString(".")
|
||||
}
|
||||
if len(p.name) > 0 {
|
||||
buf.WriteString(p.name)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "[%s]", p.index)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
506
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/validation.go
generated
vendored
Normal file
506
vendor/sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/validation.go
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
|
||||
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/util/validation/validation.go
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const qnameCharFmt string = "[A-Za-z0-9]"
|
||||
const qnameExtCharFmt string = "[-A-Za-z0-9_.]"
|
||||
const qualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt
|
||||
const qualifiedNameErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
const qualifiedNameMaxLength int = 63
|
||||
|
||||
var qualifiedNameRegexp = regexp.MustCompile("^" + qualifiedNameFmt + "$")
|
||||
|
||||
// IsQualifiedName tests whether the value passed is what Kubernetes calls a
|
||||
// "qualified name". This is a format used in various places throughout the
|
||||
// system. If the value is not valid, a list of error strings is returned.
|
||||
// Otherwise an empty list (or nil) is returned.
|
||||
func IsQualifiedName(value string) []string {
|
||||
var errs []string
|
||||
parts := strings.Split(value, "/")
|
||||
var name string
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
name = parts[0]
|
||||
case 2:
|
||||
var prefix string
|
||||
prefix, name = parts[0], parts[1]
|
||||
if len(prefix) == 0 {
|
||||
errs = append(errs, "prefix part "+EmptyError())
|
||||
} else if msgs := IsDNS1123Subdomain(prefix); len(msgs) != 0 {
|
||||
errs = append(errs, prefixEach(msgs, "prefix part ")...)
|
||||
}
|
||||
default:
|
||||
return append(errs, "a qualified name "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc")+
|
||||
" with an optional DNS subdomain prefix and '/' (e.g. 'example.com/MyName')")
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
errs = append(errs, "name part "+EmptyError())
|
||||
} else if len(name) > qualifiedNameMaxLength {
|
||||
errs = append(errs, "name part "+MaxLenError(qualifiedNameMaxLength))
|
||||
}
|
||||
if !qualifiedNameRegexp.MatchString(name) {
|
||||
errs = append(errs, "name part "+RegexError(qualifiedNameErrMsg, qualifiedNameFmt, "MyName", "my.name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsFullyQualifiedName checks if the name is fully qualified. This is similar
|
||||
// to IsFullyQualifiedDomainName but requires a minimum of 3 segments instead of
|
||||
// 2 and does not accept a trailing . as valid.
|
||||
// TODO: This function is deprecated and preserved until all callers migrate to
|
||||
// IsFullyQualifiedDomainName; please don't add new callers.
|
||||
func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
return append(allErrors, field.Required(fldPath, ""))
|
||||
}
|
||||
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||
}
|
||||
if len(strings.Split(name, ".")) < 3 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least three segments separated by dots"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsFullyQualifiedDomainName checks if the domain name is fully qualified. This
|
||||
// is similar to IsFullyQualifiedName but only requires a minimum of 2 segments
|
||||
// instead of 3 and accepts a trailing . as valid.
|
||||
func IsFullyQualifiedDomainName(fldPath *field.Path, name string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if len(name) == 0 {
|
||||
return append(allErrors, field.Required(fldPath, ""))
|
||||
}
|
||||
if strings.HasSuffix(name, ".") {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
if errs := IsDNS1123Subdomain(name); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ",")))
|
||||
}
|
||||
if len(strings.Split(name, ".")) < 2 {
|
||||
return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least two segments separated by dots"))
|
||||
}
|
||||
for _, label := range strings.Split(name, ".") {
|
||||
if errs := IsDNS1123Label(label); len(errs) > 0 {
|
||||
return append(allErrors, field.Invalid(fldPath, label, strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// Allowed characters in an HTTP Path as defined by RFC 3986. A HTTP path may
|
||||
// contain:
|
||||
// * unreserved characters (alphanumeric, '-', '.', '_', '~')
|
||||
// * percent-encoded octets
|
||||
// * sub-delims ("!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=")
|
||||
// * a colon character (":")
|
||||
const httpPathFmt string = `[A-Za-z0-9/\-._~%!$&'()*+,;=:]+`
|
||||
|
||||
var httpPathRegexp = regexp.MustCompile("^" + httpPathFmt + "$")
|
||||
|
||||
// IsDomainPrefixedPath checks if the given string is a domain-prefixed path
|
||||
// (e.g. acme.io/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
func IsDomainPrefixedPath(fldPath *field.Path, dpPath string) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if len(dpPath) == 0 {
|
||||
return append(allErrs, field.Required(fldPath, ""))
|
||||
}
|
||||
|
||||
segments := strings.SplitN(dpPath, "/", 2)
|
||||
if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
|
||||
return append(allErrs, field.Invalid(fldPath, dpPath, "must be a domain-prefixed path (such as \"acme.io/foo\")"))
|
||||
}
|
||||
|
||||
host := segments[0]
|
||||
for _, err := range IsDNS1123Subdomain(host) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, host, err))
|
||||
}
|
||||
|
||||
path := segments[1]
|
||||
if !httpPathRegexp.MatchString(path) {
|
||||
return append(allErrs, field.Invalid(fldPath, path, RegexError("Invalid path", httpPathFmt)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
const labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||
const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
// LabelValueMaxLength is a label's max length
|
||||
const LabelValueMaxLength int = 63
|
||||
|
||||
var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$")
|
||||
|
||||
// IsValidLabelValue tests whether the value passed is a valid label value. If
|
||||
// the value is not valid, a list of error strings is returned. Otherwise an
|
||||
// empty list (or nil) is returned.
|
||||
func IsValidLabelValue(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > LabelValueMaxLength {
|
||||
errs = append(errs, MaxLenError(LabelValueMaxLength))
|
||||
}
|
||||
if !labelValueRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(labelValueErrMsg, labelValueFmt, "MyValue", "my_value", "12345"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
|
||||
const dns1123LabelErrMsg string = "a DNS-1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character"
|
||||
|
||||
// DNS1123LabelMaxLength is a label's max length in DNS (RFC 1123)
|
||||
const DNS1123LabelMaxLength int = 63
|
||||
|
||||
var dns1123LabelRegexp = regexp.MustCompile("^" + dns1123LabelFmt + "$")
|
||||
|
||||
// IsDNS1123Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 1123).
|
||||
func IsDNS1123Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123LabelMaxLength))
|
||||
}
|
||||
if !dns1123LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1123LabelErrMsg, dns1123LabelFmt, "my-name", "123-abc"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1123SubdomainFmt string = dns1123LabelFmt + "(\\." + dns1123LabelFmt + ")*"
|
||||
const dns1123SubdomainErrorMsg string = "a DNS-1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
// DNS1123SubdomainMaxLength is a subdomain's max length in DNS (RFC 1123)
|
||||
const DNS1123SubdomainMaxLength int = 253
|
||||
|
||||
var dns1123SubdomainRegexp = regexp.MustCompile("^" + dns1123SubdomainFmt + "$")
|
||||
|
||||
// IsDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// subdomain in DNS (RFC 1123).
|
||||
func IsDNS1123Subdomain(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !dns1123SubdomainRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1123SubdomainErrorMsg, dns1123SubdomainFmt, "example.com"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const dns1035LabelFmt string = "[a-z]([-a-z0-9]*[a-z0-9])?"
|
||||
const dns1035LabelErrMsg string = "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character"
|
||||
|
||||
// DNS1035LabelMaxLength is a label's max length in DNS (RFC 1035)
|
||||
const DNS1035LabelMaxLength int = 63
|
||||
|
||||
var dns1035LabelRegexp = regexp.MustCompile("^" + dns1035LabelFmt + "$")
|
||||
|
||||
// IsDNS1035Label tests for a string that conforms to the definition of a label in
|
||||
// DNS (RFC 1035).
|
||||
func IsDNS1035Label(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1035LabelMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1035LabelMaxLength))
|
||||
}
|
||||
if !dns1035LabelRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(dns1035LabelErrMsg, dns1035LabelFmt, "my-name", "abc-123"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// wildcard definition - RFC 1034 section 4.3.3.
|
||||
// examples:
|
||||
// - valid: *.bar.com, *.foo.bar.com
|
||||
// - invalid: *.*.bar.com, *.foo.*.com, *bar.com, f*.bar.com, *
|
||||
const wildcardDNS1123SubdomainFmt = "\\*\\." + dns1123SubdomainFmt
|
||||
const wildcardDNS1123SubdomainErrMsg = "a wildcard DNS-1123 subdomain must start with '*.', followed by a valid DNS subdomain, which must consist of lower case alphanumeric characters, '-' or '.' and end with an alphanumeric character"
|
||||
|
||||
// IsWildcardDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// wildcard subdomain in DNS (RFC 1034 section 4.3.3).
|
||||
func IsWildcardDNS1123Subdomain(value string) []string {
|
||||
wildcardDNS1123SubdomainRegexp := regexp.MustCompile("^" + wildcardDNS1123SubdomainFmt + "$")
|
||||
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !wildcardDNS1123SubdomainRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(wildcardDNS1123SubdomainErrMsg, wildcardDNS1123SubdomainFmt, "*.example.com"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const cIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
|
||||
const identifierErrMsg string = "a valid C identifier must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'"
|
||||
|
||||
var cIdentifierRegexp = regexp.MustCompile("^" + cIdentifierFmt + "$")
|
||||
|
||||
// IsCIdentifier tests for a string that conforms the definition of an identifier
|
||||
// in C. This checks the format, but not the length.
|
||||
func IsCIdentifier(value string) []string {
|
||||
if !cIdentifierRegexp.MatchString(value) {
|
||||
return []string{RegexError(identifierErrMsg, cIdentifierFmt, "my_name", "MY_NAME", "MyName")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidPortNum tests that the argument is a valid, non-zero port number.
|
||||
func IsValidPortNum(port int) []string {
|
||||
if 1 <= port && port <= 65535 {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(1, 65535)}
|
||||
}
|
||||
|
||||
// IsInRange tests that the argument is in an inclusive range.
|
||||
func IsInRange(value int, min int, max int) []string {
|
||||
if value >= min && value <= max {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(min, max)}
|
||||
}
|
||||
|
||||
// Now in libcontainer UID/GID limits is 0 ~ 1<<31 - 1
|
||||
// TODO: once we have a type for UID/GID we should make these that type.
|
||||
const (
|
||||
minUserID = 0
|
||||
maxUserID = math.MaxInt32
|
||||
minGroupID = 0
|
||||
maxGroupID = math.MaxInt32
|
||||
)
|
||||
|
||||
// IsValidGroupID tests that the argument is a valid Unix GID.
|
||||
func IsValidGroupID(gid int64) []string {
|
||||
if minGroupID <= gid && gid <= maxGroupID {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(minGroupID, maxGroupID)}
|
||||
}
|
||||
|
||||
// IsValidUserID tests that the argument is a valid Unix UID.
|
||||
func IsValidUserID(uid int64) []string {
|
||||
if minUserID <= uid && uid <= maxUserID {
|
||||
return nil
|
||||
}
|
||||
return []string{InclusiveRangeError(minUserID, maxUserID)}
|
||||
}
|
||||
|
||||
var portNameCharsetRegex = regexp.MustCompile("^[-a-z0-9]+$")
|
||||
var portNameOneLetterRegexp = regexp.MustCompile("[a-z]")
|
||||
|
||||
// IsValidPortName check that the argument is valid syntax. It must be
|
||||
// non-empty and no more than 15 characters long. It may contain only [-a-z0-9]
|
||||
// and must contain at least one letter [a-z]. It must not start or end with a
|
||||
// hyphen, nor contain adjacent hyphens.
|
||||
//
|
||||
// Note: We only allow lower-case characters, even though RFC 6335 is case
|
||||
// insensitive.
|
||||
func IsValidPortName(port string) []string {
|
||||
var errs []string
|
||||
if len(port) > 15 {
|
||||
errs = append(errs, MaxLenError(15))
|
||||
}
|
||||
if !portNameCharsetRegex.MatchString(port) {
|
||||
errs = append(errs, "must contain only alpha-numeric characters (a-z, 0-9), and hyphens (-)")
|
||||
}
|
||||
if !portNameOneLetterRegexp.MatchString(port) {
|
||||
errs = append(errs, "must contain at least one letter or number (a-z, 0-9)")
|
||||
}
|
||||
if strings.Contains(port, "--") {
|
||||
errs = append(errs, "must not contain consecutive hyphens")
|
||||
}
|
||||
if len(port) > 0 && (port[0] == '-' || port[len(port)-1] == '-') {
|
||||
errs = append(errs, "must not begin or end with a hyphen")
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsValidIP tests that the argument is a valid IP address.
|
||||
func IsValidIP(value string) []string {
|
||||
if net.ParseIP(value) == nil {
|
||||
return []string{"must be a valid IP address, (e.g. 10.9.8.7)"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidIPv4Address tests that the argument is a valid IPv4 address.
|
||||
func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() == nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// IsValidIPv6Address tests that the argument is a valid IPv6 address.
|
||||
func IsValidIPv6Address(fldPath *field.Path, value string) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil || ip.To4() != nil {
|
||||
allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address"))
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
const percentFmt string = "[0-9]+%"
|
||||
const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'"
|
||||
|
||||
var percentRegexp = regexp.MustCompile("^" + percentFmt + "$")
|
||||
|
||||
// IsValidPercent checks that string is in the form of a percentage
|
||||
func IsValidPercent(percent string) []string {
|
||||
if !percentRegexp.MatchString(percent) {
|
||||
return []string{RegexError(percentErrMsg, percentFmt, "1%", "93%")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const httpHeaderNameFmt string = "[-A-Za-z0-9]+"
|
||||
const httpHeaderNameErrMsg string = "a valid HTTP header must consist of alphanumeric characters or '-'"
|
||||
|
||||
var httpHeaderNameRegexp = regexp.MustCompile("^" + httpHeaderNameFmt + "$")
|
||||
|
||||
// IsHTTPHeaderName checks that a string conforms to the Go HTTP library's
|
||||
// definition of a valid header field name (a stricter subset than RFC7230).
|
||||
func IsHTTPHeaderName(value string) []string {
|
||||
if !httpHeaderNameRegexp.MatchString(value) {
|
||||
return []string{RegexError(httpHeaderNameErrMsg, httpHeaderNameFmt, "X-Header-Name")}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const envVarNameFmt = "[-._a-zA-Z][-._a-zA-Z0-9]*"
|
||||
const envVarNameFmtErrMsg string = "a valid environment variable name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit"
|
||||
|
||||
var envVarNameRegexp = regexp.MustCompile("^" + envVarNameFmt + "$")
|
||||
|
||||
// IsEnvVarName tests if a string is a valid environment variable name.
|
||||
func IsEnvVarName(value string) []string {
|
||||
var errs []string
|
||||
if !envVarNameRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(envVarNameFmtErrMsg, envVarNameFmt, "my.env-name", "MY_ENV.NAME", "MyEnvName1"))
|
||||
}
|
||||
|
||||
errs = append(errs, hasChDirPrefix(value)...)
|
||||
return errs
|
||||
}
|
||||
|
||||
const configMapKeyFmt = `[-._a-zA-Z0-9]+`
|
||||
const configMapKeyErrMsg string = "a valid config key must consist of alphanumeric characters, '-', '_' or '.'"
|
||||
|
||||
var configMapKeyRegexp = regexp.MustCompile("^" + configMapKeyFmt + "$")
|
||||
|
||||
// IsConfigMapKey tests for a string that is a valid key for a ConfigMap or Secret
|
||||
func IsConfigMapKey(value string) []string {
|
||||
var errs []string
|
||||
if len(value) > DNS1123SubdomainMaxLength {
|
||||
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||
}
|
||||
if !configMapKeyRegexp.MatchString(value) {
|
||||
errs = append(errs, RegexError(configMapKeyErrMsg, configMapKeyFmt, "key.name", "KEY_NAME", "key-name"))
|
||||
}
|
||||
errs = append(errs, hasChDirPrefix(value)...)
|
||||
return errs
|
||||
}
|
||||
|
||||
// MaxLenError returns a string explanation of a "string too long" validation
|
||||
// failure.
|
||||
func MaxLenError(length int) string {
|
||||
return fmt.Sprintf("must be no more than %d characters", length)
|
||||
}
|
||||
|
||||
// RegexError returns a string explanation of a regex validation failure.
|
||||
func RegexError(msg string, fmt string, examples ...string) string {
|
||||
if len(examples) == 0 {
|
||||
return msg + " (regex used for validation is '" + fmt + "')"
|
||||
}
|
||||
msg += " (e.g. "
|
||||
for i := range examples {
|
||||
if i > 0 {
|
||||
msg += " or "
|
||||
}
|
||||
msg += "'" + examples[i] + "', "
|
||||
}
|
||||
msg += "regex used for validation is '" + fmt + "')"
|
||||
return msg
|
||||
}
|
||||
|
||||
// EmptyError returns a string explanation of a "must not be empty" validation
|
||||
// failure.
|
||||
func EmptyError() string {
|
||||
return "must be non-empty"
|
||||
}
|
||||
|
||||
func prefixEach(msgs []string, prefix string) []string {
|
||||
for i := range msgs {
|
||||
msgs[i] = prefix + msgs[i]
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
||||
// InclusiveRangeError returns a string explanation of a numeric "must be
|
||||
// between" validation failure.
|
||||
func InclusiveRangeError(lo, hi int) string {
|
||||
return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi)
|
||||
}
|
||||
|
||||
func hasChDirPrefix(value string) []string {
|
||||
var errs []string
|
||||
switch {
|
||||
case value == ".":
|
||||
errs = append(errs, `must not be '.'`)
|
||||
case value == "..":
|
||||
errs = append(errs, `must not be '..'`)
|
||||
case strings.HasPrefix(value, ".."):
|
||||
errs = append(errs, `must not start with '..'`)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// IsValidSocketAddr checks that string represents a valid socket address
|
||||
// as defined in RFC 789. (e.g 0.0.0.0:10254 or [::]:10254))
|
||||
func IsValidSocketAddr(value string) []string {
|
||||
var errs []string
|
||||
ip, port, err := net.SplitHostPort(value)
|
||||
if err != nil {
|
||||
errs = append(errs, "must be a valid socket address format, (e.g. 0.0.0.0:10254 or [::]:10254)")
|
||||
return errs
|
||||
}
|
||||
portInt, _ := strconv.Atoi(port)
|
||||
errs = append(errs, IsValidPortNum(portInt)...)
|
||||
errs = append(errs, IsValidIP(ip)...)
|
||||
return errs
|
||||
}
|
||||
137
vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go
generated
vendored
Normal file
137
vendor/sigs.k8s.io/kustomize/kyaml/yaml/kfns.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// AnnotationClearer removes an annotation at metadata.annotations.
|
||||
// Returns nil if the annotation or field does not exist.
|
||||
type AnnotationClearer struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (c AnnotationClearer) Filter(rn *RNode) (*RNode, error) {
|
||||
return rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField, AnnotationsField}},
|
||||
FieldClearer{Name: c.Key})
|
||||
}
|
||||
|
||||
func ClearAnnotation(key string) AnnotationClearer {
|
||||
return AnnotationClearer{Key: key}
|
||||
}
|
||||
|
||||
// ClearEmptyAnnotations clears the keys, annotations
|
||||
// and metadata if they are empty/null
|
||||
func ClearEmptyAnnotations(rn *RNode) error {
|
||||
_, err := rn.Pipe(Lookup(MetadataField), FieldClearer{
|
||||
Name: AnnotationsField, IfEmpty: true})
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
_, err = rn.Pipe(FieldClearer{Name: MetadataField, IfEmpty: true})
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// k8sMetaSetter sets a name at metadata.{key}.
|
||||
// Creates metadata if does not exist.
|
||||
type k8sMetaSetter struct {
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s k8sMetaSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
_, err := rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField}, Create: yaml.MappingNode},
|
||||
FieldSetter{Name: s.Key, Value: NewStringRNode(s.Value)})
|
||||
return rn, err
|
||||
}
|
||||
|
||||
func SetK8sName(value string) k8sMetaSetter {
|
||||
return k8sMetaSetter{Key: NameField, Value: value}
|
||||
}
|
||||
|
||||
func SetK8sNamespace(value string) k8sMetaSetter {
|
||||
return k8sMetaSetter{Key: NamespaceField, Value: value}
|
||||
}
|
||||
|
||||
// AnnotationSetter sets an annotation at metadata.annotations.
|
||||
// Creates metadata.annotations if does not exist.
|
||||
type AnnotationSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s AnnotationSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v := NewStringRNode(s.Value)
|
||||
// some tools get confused about the type if annotations are not quoted
|
||||
v.YNode().Style = yaml.SingleQuotedStyle
|
||||
if err := ClearEmptyAnnotations(rn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return addMetadataNode(rn, AnnotationsField, s.Key, v)
|
||||
}
|
||||
|
||||
func SetAnnotation(key, value string) AnnotationSetter {
|
||||
return AnnotationSetter{Key: key, Value: value}
|
||||
}
|
||||
|
||||
// AnnotationGetter gets an annotation at metadata.annotations.
|
||||
// Returns nil if metadata.annotations does not exist.
|
||||
type AnnotationGetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
// AnnotationGetter returns the annotation value.
|
||||
// Returns "", nil if the annotation does not exist.
|
||||
func (g AnnotationGetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v, err := rn.Pipe(
|
||||
PathGetter{Path: []string{MetadataField, AnnotationsField, g.Key}})
|
||||
if v == nil || err != nil {
|
||||
return v, err
|
||||
}
|
||||
if g.Value == "" || v.value.Value == g.Value {
|
||||
return v, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetAnnotation(key string) AnnotationGetter {
|
||||
return AnnotationGetter{Key: key}
|
||||
}
|
||||
|
||||
// LabelSetter sets a label at metadata.labels.
|
||||
// Creates metadata.labels if does not exist.
|
||||
type LabelSetter struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Key string `yaml:"key,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (s LabelSetter) Filter(rn *RNode) (*RNode, error) {
|
||||
v := NewStringRNode(s.Value)
|
||||
// some tools get confused about the type if labels are not quoted
|
||||
v.YNode().Style = yaml.SingleQuotedStyle
|
||||
return addMetadataNode(rn, LabelsField, s.Key, v)
|
||||
}
|
||||
|
||||
func addMetadataNode(rn *RNode, field, key string, v *RNode) (*RNode, error) {
|
||||
return rn.Pipe(
|
||||
PathGetter{
|
||||
Path: []string{MetadataField, field}, Create: yaml.MappingNode},
|
||||
FieldSetter{Name: key, Value: v})
|
||||
}
|
||||
|
||||
func SetLabel(key, value string) LabelSetter {
|
||||
return LabelSetter{Key: key, Value: value}
|
||||
}
|
||||
40
vendor/sigs.k8s.io/kustomize/kyaml/yaml/mapnode.go
generated
vendored
Normal file
40
vendor/sigs.k8s.io/kustomize/kyaml/yaml/mapnode.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
// MapNode wraps a field key and value.
|
||||
type MapNode struct {
|
||||
Key *RNode
|
||||
Value *RNode
|
||||
}
|
||||
|
||||
// IsNilOrEmpty returns true if the MapNode is nil,
|
||||
// has no value, or has a value that appears empty.
|
||||
func (mn *MapNode) IsNilOrEmpty() bool {
|
||||
return mn == nil || mn.Value.IsNilOrEmpty()
|
||||
}
|
||||
|
||||
type MapNodeSlice []*MapNode
|
||||
|
||||
func (m MapNodeSlice) Keys() []*RNode {
|
||||
var keys []*RNode
|
||||
for i := range m {
|
||||
if m[i] != nil {
|
||||
keys = append(keys, m[i].Key)
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m MapNodeSlice) Values() []*RNode {
|
||||
var values []*RNode
|
||||
for i := range m {
|
||||
if m[i] != nil {
|
||||
values = append(values, m[i].Value)
|
||||
} else {
|
||||
values = append(values, nil)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/match.go
generated
vendored
Normal file
206
vendor/sigs.k8s.io/kustomize/kyaml/yaml/match.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PathMatcher returns all RNodes matching the path wrapped in a SequenceNode.
|
||||
// Lists may have multiple elements matching the path, and each matching element
|
||||
// is added to the return result.
|
||||
// If Path points to a SequenceNode, the SequenceNode is wrapped in another SequenceNode
|
||||
// If Path does not contain any lists, the result is still wrapped in a SequenceNode of len == 1
|
||||
type PathMatcher struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// Path is a slice of parts leading to the RNode to lookup.
|
||||
// Each path part may be one of:
|
||||
// * FieldMatcher -- e.g. "spec"
|
||||
// * Map Key -- e.g. "app.k8s.io/version"
|
||||
// * List Entry -- e.g. "[name=nginx]" or "[=-jar]"
|
||||
//
|
||||
// Map Keys and Fields are equivalent.
|
||||
// See FieldMatcher for more on Fields and Map Keys.
|
||||
//
|
||||
// List Entries are specified as map entry to match [fieldName=fieldValue].
|
||||
// See Elem for more on List Entries.
|
||||
//
|
||||
// Examples:
|
||||
// * spec.template.spec.container with matching name: [name=nginx] -- match 'name': 'nginx'
|
||||
// * spec.template.spec.container.argument matching a value: [=-jar] -- match '-jar'
|
||||
Path []string `yaml:"path,omitempty"`
|
||||
|
||||
// Matches is set by PathMatch to publish the matched element values for each node.
|
||||
// After running PathMatcher.Filter, each node from the SequenceNode result may be
|
||||
// looked up in Matches to find the field values that were matched.
|
||||
Matches map[*Node][]string
|
||||
|
||||
// StripComments may be set to remove the comments on the matching Nodes.
|
||||
// This is useful for if the nodes are to be printed in FlowStyle.
|
||||
StripComments bool
|
||||
|
||||
val *RNode
|
||||
field string
|
||||
matchRegex string
|
||||
}
|
||||
|
||||
func (p *PathMatcher) stripComments(n *Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
if p.StripComments {
|
||||
n.LineComment = ""
|
||||
n.HeadComment = ""
|
||||
n.FootComment = ""
|
||||
for i := range n.Content {
|
||||
p.stripComments(n.Content[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PathMatcher) Filter(rn *RNode) (*RNode, error) {
|
||||
val, err := p.filter(rn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.stripComments(val.YNode())
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (p *PathMatcher) filter(rn *RNode) (*RNode, error) {
|
||||
p.Matches = map[*Node][]string{}
|
||||
|
||||
if len(p.Path) == 0 {
|
||||
// return the element wrapped in a SequenceNode
|
||||
p.appendRNode("", rn)
|
||||
return p.val, nil
|
||||
}
|
||||
|
||||
if IsListIndex(p.Path[0]) {
|
||||
// match seq elements
|
||||
return p.doSeq(rn)
|
||||
}
|
||||
// match a field
|
||||
return p.doField(rn)
|
||||
}
|
||||
|
||||
func (p *PathMatcher) doField(rn *RNode) (*RNode, error) {
|
||||
// lookup the field
|
||||
field, err := rn.Pipe(Get(p.Path[0]))
|
||||
if err != nil || field == nil {
|
||||
// if the field doesn't exist, return nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// recurse on the field, removing the first element of the path
|
||||
pm := &PathMatcher{Path: p.Path[1:]}
|
||||
p.val, err = pm.filter(field)
|
||||
p.Matches = pm.Matches
|
||||
return p.val, err
|
||||
}
|
||||
|
||||
// doSeq iterates over a sequence and appends elements matching the path regex to p.Val
|
||||
func (p *PathMatcher) doSeq(rn *RNode) (*RNode, error) {
|
||||
// parse the field + match pair
|
||||
var err error
|
||||
p.field, p.matchRegex, err = SplitIndexNameValue(p.Path[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p.field == "" {
|
||||
err = rn.VisitElements(p.visitPrimitiveElem)
|
||||
} else {
|
||||
err = rn.VisitElements(p.visitElem)
|
||||
}
|
||||
if err != nil || p.val == nil || len(p.val.YNode().Content) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.val, nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) visitPrimitiveElem(elem *RNode) error {
|
||||
r, err := regexp.Compile(p.matchRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
str, err := elem.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if !r.MatchString(str) {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.appendRNode("", elem)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) visitElem(elem *RNode) error {
|
||||
r, err := regexp.Compile(p.matchRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if this elements field matches the regex
|
||||
val := elem.Field(p.field)
|
||||
if val == nil || val.Value == nil {
|
||||
return nil
|
||||
}
|
||||
str, err := val.Value.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
if !r.MatchString(str) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// recurse on the matching element
|
||||
pm := &PathMatcher{Path: p.Path[1:]}
|
||||
add, err := pm.filter(elem)
|
||||
for k, v := range pm.Matches {
|
||||
p.Matches[k] = v
|
||||
}
|
||||
if err != nil || add == nil {
|
||||
return err
|
||||
}
|
||||
p.append(str, add.Content()...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PathMatcher) appendRNode(path string, node *RNode) {
|
||||
p.append(path, node.YNode())
|
||||
}
|
||||
|
||||
func (p *PathMatcher) append(path string, nodes ...*Node) {
|
||||
if p.val == nil {
|
||||
p.val = NewRNode(&Node{Kind: SequenceNode})
|
||||
}
|
||||
for i := range nodes {
|
||||
node := nodes[i]
|
||||
p.val.YNode().Content = append(p.val.YNode().Content, node)
|
||||
// record the path if specified
|
||||
if path != "" {
|
||||
p.Matches[node] = append(p.Matches[node], path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanPath(path []string) []string {
|
||||
var p []string
|
||||
for _, elem := range path {
|
||||
elem = strings.TrimSpace(elem)
|
||||
if len(elem) == 0 {
|
||||
continue
|
||||
}
|
||||
p = append(p, elem)
|
||||
}
|
||||
return p
|
||||
}
|
||||
107
vendor/sigs.k8s.io/kustomize/kyaml/yaml/order.go
generated
vendored
Normal file
107
vendor/sigs.k8s.io/kustomize/kyaml/yaml/order.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
// fieldSortOrder contains the relative ordering of fields when formatting an
|
||||
// object.
|
||||
var fieldSortOrder = []string{
|
||||
// top-level metadata
|
||||
"name", "generateName", "namespace", "clusterName",
|
||||
"apiVersion", "kind", "metadata", "type",
|
||||
"labels", "annotations",
|
||||
"spec", "status",
|
||||
|
||||
// secret and configmap
|
||||
"stringData", "data", "binaryData",
|
||||
|
||||
// cronjobspec, daemonsetspec, deploymentspec, statefulsetspec,
|
||||
// jobspec fields
|
||||
"parallelism", "completions", "activeDeadlineSeconds", "backoffLimit",
|
||||
"replicas", "selector", "manualSelector", "template",
|
||||
"ttlSecondsAfterFinished", "volumeClaimTemplates", "service", "serviceName",
|
||||
"podManagementPolicy", "updateStrategy", "strategy", "minReadySeconds",
|
||||
"revision", "revisionHistoryLimit", "paused", "progressDeadlineSeconds",
|
||||
|
||||
// podspec
|
||||
// podspec scalars
|
||||
"restartPolicy", "terminationGracePeriodSeconds",
|
||||
"activeDeadlineSeconds", "dnsPolicy", "serviceAccountName",
|
||||
"serviceAccount", "automountServiceAccountToken", "nodeName",
|
||||
"hostNetwork", "hostPID", "hostIPC", "shareProcessNamespace", "hostname",
|
||||
"subdomain", "schedulerName", "priorityClassName", "priority",
|
||||
"runtimeClassName", "enableServiceLinks",
|
||||
|
||||
// podspec lists and maps
|
||||
"nodeSelector", "hostAliases",
|
||||
|
||||
// podspec objects
|
||||
"initContainers", "containers", "volumes", "securityContext",
|
||||
"imagePullSecrets", "affinity", "tolerations", "dnsConfig",
|
||||
"readinessGates",
|
||||
|
||||
// containers
|
||||
"image", "command", "args", "workingDir", "ports", "envFrom", "env",
|
||||
"resources", "volumeMounts", "volumeDevices", "livenessProbe",
|
||||
"readinessProbe", "lifecycle", "terminationMessagePath",
|
||||
"terminationMessagePolicy", "imagePullPolicy", "securityContext",
|
||||
"stdin", "stdinOnce", "tty",
|
||||
|
||||
// service
|
||||
"clusterIP", "externalIPs", "loadBalancerIP", "loadBalancerSourceRanges",
|
||||
"externalName", "externalTrafficPolicy", "sessionAffinity",
|
||||
|
||||
// ports
|
||||
"protocol", "port", "targetPort", "hostPort", "containerPort", "hostIP",
|
||||
|
||||
// volumemount
|
||||
"readOnly", "mountPath", "subPath", "subPathExpr", "mountPropagation",
|
||||
|
||||
// envvar + envvarsource
|
||||
"value", "valueFrom", "fieldRef", "resourceFieldRef", "configMapKeyRef",
|
||||
"secretKeyRef", "prefix", "configMapRef", "secretRef",
|
||||
}
|
||||
|
||||
type set map[string]interface{}
|
||||
|
||||
func newSet(values ...string) set {
|
||||
m := map[string]interface{}{}
|
||||
for _, value := range values {
|
||||
m[value] = nil
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (s set) Has(key string) bool {
|
||||
_, found := s[key]
|
||||
return found
|
||||
}
|
||||
|
||||
// WhitelistedListSortKinds contains the set of kinds that are whitelisted
|
||||
// for sorting list field elements
|
||||
var WhitelistedListSortKinds = newSet(
|
||||
"CronJob", "DaemonSet", "Deployment", "Job", "ReplicaSet", "StatefulSet",
|
||||
"ValidatingWebhookConfiguration")
|
||||
|
||||
// WhitelistedListSortApis contains the set of apis that are whitelisted for
|
||||
// sorting list field elements
|
||||
var WhitelistedListSortApis = newSet(
|
||||
"apps/v1", "apps/v1beta1", "apps/v1beta2", "batch/v1", "batch/v1beta1",
|
||||
"extensions/v1beta1", "v1", "admissionregistration.k8s.io/v1")
|
||||
|
||||
// WhitelistedListSortFields contains json paths to list fields that should
|
||||
// be sorted, and the field they should be sorted by
|
||||
var WhitelistedListSortFields = map[string]string{
|
||||
".spec.template.spec.containers": "name",
|
||||
".webhooks.rules.operations": "",
|
||||
}
|
||||
|
||||
// FieldOrder indexes fields and maps them to relative precedence
|
||||
var FieldOrder = func() map[string]int {
|
||||
// create an index of field orderings
|
||||
fo := map[string]int{}
|
||||
for i, f := range fieldSortOrder {
|
||||
fo[f] = i + 1
|
||||
}
|
||||
return fo
|
||||
}()
|
||||
1008
vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go
generated
vendored
Normal file
1008
vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
76
vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go
generated
vendored
Normal file
76
vendor/sigs.k8s.io/kustomize/kyaml/yaml/serialization.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
func DoSerializationHacksOnNodes(nodes []*RNode) {
|
||||
for _, node := range nodes {
|
||||
DoSerializationHacks(node.YNode())
|
||||
}
|
||||
}
|
||||
|
||||
// DoSerializationHacks addresses a bug in yaml V3 upstream, it parses the yaml node,
|
||||
// and rearranges the head comments of the children of sequence node.
|
||||
// Refer to https://github.com/go-yaml/yaml/issues/587 for more details
|
||||
func DoSerializationHacks(node *yaml.Node) {
|
||||
switch node.Kind {
|
||||
case DocumentNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case MappingNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case SequenceNode:
|
||||
for _, node := range node.Content {
|
||||
// for each child mapping node, transfer the head comment of it's
|
||||
// first child scalar node to the head comment of itself
|
||||
// This is necessary to address serialization issue
|
||||
// https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3
|
||||
// Remove this hack when the issue has been resolved
|
||||
if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode {
|
||||
node.HeadComment = node.Content[0].HeadComment
|
||||
node.Content[0].HeadComment = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func UndoSerializationHacksOnNodes(nodes []*RNode) {
|
||||
for _, node := range nodes {
|
||||
UndoSerializationHacks(node.YNode())
|
||||
}
|
||||
}
|
||||
|
||||
// UndoSerializationHacks reverts the changes made by DoSerializationHacks
|
||||
// Refer to https://github.com/go-yaml/yaml/issues/587 for more details
|
||||
func UndoSerializationHacks(node *yaml.Node) {
|
||||
switch node.Kind {
|
||||
case DocumentNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case MappingNode:
|
||||
for _, node := range node.Content {
|
||||
DoSerializationHacks(node)
|
||||
}
|
||||
|
||||
case SequenceNode:
|
||||
for _, node := range node.Content {
|
||||
// revert the changes made in DoSerializationHacks
|
||||
// This is necessary to address serialization issue
|
||||
// https://github.com/go-yaml/yaml/issues/587 in go-yaml.v3
|
||||
// Remove this hack when the issue has been resolved
|
||||
if len(node.Content) > 0 && node.Content[0].Kind == ScalarNode {
|
||||
node.Content[0].HeadComment = node.HeadComment
|
||||
node.HeadComment = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go
generated
vendored
Normal file
237
vendor/sigs.k8s.io/kustomize/kyaml/yaml/types.go
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/sets"
|
||||
)
|
||||
|
||||
// CopyYNode returns a distinct copy of its argument.
|
||||
// Use https://github.com/jinzhu/copier instead?
|
||||
func CopyYNode(n *yaml.Node) *yaml.Node {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
c := *n
|
||||
if len(n.Content) > 0 {
|
||||
// Using Go 'copy' here doesn't yield independent slices.
|
||||
c.Content = make([]*Node, len(n.Content))
|
||||
for i, item := range n.Content {
|
||||
c.Content[i] = CopyYNode(item)
|
||||
}
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
// IsYNodeTaggedNull returns true if the node is explicitly tagged Null.
|
||||
func IsYNodeTaggedNull(n *yaml.Node) bool {
|
||||
return n != nil && n.Tag == NodeTagNull
|
||||
}
|
||||
|
||||
// IsYNodeEmptyMap is true if the Node is a non-nil empty map.
|
||||
func IsYNodeEmptyMap(n *yaml.Node) bool {
|
||||
return n != nil && n.Kind == yaml.MappingNode && len(n.Content) == 0
|
||||
}
|
||||
|
||||
// IsYNodeEmptyMap is true if the Node is a non-nil empty sequence.
|
||||
func IsYNodeEmptySeq(n *yaml.Node) bool {
|
||||
return n != nil && n.Kind == yaml.SequenceNode && len(n.Content) == 0
|
||||
}
|
||||
|
||||
// IsYNodeEmptyDoc is true if the node is a Document with no content.
|
||||
// E.g.: "---\n---"
|
||||
func IsYNodeEmptyDoc(n *yaml.Node) bool {
|
||||
return n.Kind == yaml.DocumentNode && n.Content[0].Tag == NodeTagNull
|
||||
}
|
||||
|
||||
func IsYNodeString(n *yaml.Node) bool {
|
||||
return n.Kind == yaml.ScalarNode &&
|
||||
(n.Tag == NodeTagString || n.Tag == NodeTagEmpty)
|
||||
}
|
||||
|
||||
// IsYNodeZero is true if all the public fields in the Node are empty.
|
||||
// Which means it's not initialized and should be omitted when marshal.
|
||||
// The Node itself has a method IsZero but it is not released
|
||||
// in yaml.v3. https://pkg.go.dev/gopkg.in/yaml.v3#Node.IsZero
|
||||
func IsYNodeZero(n *yaml.Node) bool {
|
||||
// TODO: Change this to use IsZero when it's avaialable.
|
||||
return n != nil && n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" &&
|
||||
n.Anchor == "" && n.Alias == nil && n.Content == nil &&
|
||||
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" &&
|
||||
n.Line == 0 && n.Column == 0
|
||||
}
|
||||
|
||||
// Parser parses values into configuration.
|
||||
type Parser struct {
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (p Parser) Filter(_ *RNode) (*RNode, error) {
|
||||
d := yaml.NewDecoder(bytes.NewBuffer([]byte(p.Value)))
|
||||
o := &RNode{value: &yaml.Node{}}
|
||||
return o, d.Decode(o.value)
|
||||
}
|
||||
|
||||
// TODO(pwittrock): test this
|
||||
func GetStyle(styles ...string) Style {
|
||||
var style Style
|
||||
for _, s := range styles {
|
||||
switch s {
|
||||
case "TaggedStyle":
|
||||
style |= TaggedStyle
|
||||
case "DoubleQuotedStyle":
|
||||
style |= DoubleQuotedStyle
|
||||
case "SingleQuotedStyle":
|
||||
style |= SingleQuotedStyle
|
||||
case "LiteralStyle":
|
||||
style |= LiteralStyle
|
||||
case "FoldedStyle":
|
||||
style |= FoldedStyle
|
||||
case "FlowStyle":
|
||||
style |= FlowStyle
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
// Filter defines a function to manipulate an individual RNode such as by changing
|
||||
// its values, or returning a field.
|
||||
//
|
||||
// When possible, Filters should be serializable to yaml so that they can be described
|
||||
// declaratively as data.
|
||||
//
|
||||
// Analogous to http://www.linfo.org/filters.html
|
||||
type Filter interface {
|
||||
Filter(object *RNode) (*RNode, error)
|
||||
}
|
||||
|
||||
type FilterFunc func(object *RNode) (*RNode, error)
|
||||
|
||||
func (f FilterFunc) Filter(object *RNode) (*RNode, error) {
|
||||
return f(object)
|
||||
}
|
||||
|
||||
// TypeMeta partially copies apimachinery/pkg/apis/meta/v1.TypeMeta
|
||||
// No need for a direct dependence; the fields are stable.
|
||||
type TypeMeta struct {
|
||||
// APIVersion is the apiVersion field of a Resource
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
// Kind is the kind field of a Resource
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
}
|
||||
|
||||
// NameMeta contains name information.
|
||||
type NameMeta struct {
|
||||
// Name is the metadata.name field of a Resource
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
// Namespace is the metadata.namespace field of a Resource
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceMeta contains the metadata for a both Resource Type and Resource.
|
||||
type ResourceMeta struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
// ObjectMeta is the metadata field of a Resource
|
||||
ObjectMeta `yaml:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// ObjectMeta contains metadata about a Resource
|
||||
type ObjectMeta struct {
|
||||
NameMeta `json:",inline" yaml:",inline"`
|
||||
// Labels is the metadata.labels field of a Resource
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
// Annotations is the metadata.annotations field of a Resource.
|
||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// GetIdentifier returns a ResourceIdentifier that includes
|
||||
// the information needed to uniquely identify a resource in a cluster.
|
||||
func (m *ResourceMeta) GetIdentifier() ResourceIdentifier {
|
||||
return ResourceIdentifier{
|
||||
TypeMeta: m.TypeMeta,
|
||||
NameMeta: m.NameMeta,
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceIdentifier contains the information needed to uniquely
|
||||
// identify a resource in a cluster.
|
||||
type ResourceIdentifier struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
NameMeta `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// Comments struct is comment yaml comment types
|
||||
type Comments struct {
|
||||
LineComment string `yaml:"lineComment,omitempty"`
|
||||
HeadComment string `yaml:"headComment,omitempty"`
|
||||
FootComment string `yaml:"footComment,omitempty"`
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetName() string {
|
||||
return r.Name
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetNamespace() string {
|
||||
return r.Namespace
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetAPIVersion() string {
|
||||
return r.APIVersion
|
||||
}
|
||||
|
||||
func (r *ResourceIdentifier) GetKind() string {
|
||||
return r.Kind
|
||||
}
|
||||
|
||||
const (
|
||||
Trim = "Trim"
|
||||
Flow = "Flow"
|
||||
)
|
||||
|
||||
// String returns a string value for a Node, applying the supplied formatting options
|
||||
func String(node *yaml.Node, opts ...string) (string, error) {
|
||||
if node == nil {
|
||||
return "", nil
|
||||
}
|
||||
optsSet := sets.String{}
|
||||
optsSet.Insert(opts...)
|
||||
if optsSet.Has(Flow) {
|
||||
oldStyle := node.Style
|
||||
defer func() {
|
||||
node.Style = oldStyle
|
||||
}()
|
||||
node.Style = yaml.FlowStyle
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
e := NewEncoder(b)
|
||||
err := e.Encode(node)
|
||||
e.Close()
|
||||
val := b.String()
|
||||
if optsSet.Has(Trim) {
|
||||
val = strings.TrimSpace(val)
|
||||
}
|
||||
return val, errors.Wrap(err)
|
||||
}
|
||||
|
||||
// MergeOptionsListIncreaseDirection is the type of list growth in merge
|
||||
type MergeOptionsListIncreaseDirection int
|
||||
|
||||
const (
|
||||
MergeOptionsListAppend MergeOptionsListIncreaseDirection = iota
|
||||
MergeOptionsListPrepend
|
||||
)
|
||||
|
||||
// MergeOptions is a struct which contains the options for merge
|
||||
type MergeOptions struct {
|
||||
// ListIncreaseDirection indicates should merge function prepend the items from
|
||||
// source list to destination or append.
|
||||
ListIncreaseDirection MergeOptionsListIncreaseDirection
|
||||
}
|
||||
Reference in New Issue
Block a user