mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Refactor container function runtime into its own package
This commit is contained in:
@@ -3,15 +3,12 @@ module sigs.k8s.io/kustomize/cmd/config
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible // indirect
|
||||
github.com/cpuguy83/go-md2man v1.0.10 // indirect
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/posener/complete/v2 v2.0.1-alpha.12
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 // indirect
|
||||
k8s.io/apimachinery v0.17.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.0.0
|
||||
)
|
||||
|
||||
@@ -23,11 +23,9 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -161,7 +159,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d h1:K6eOUihrFLdZjZnA4XlRp864fmWXv9YTIk7VPLhRacA=
|
||||
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
@@ -171,15 +168,13 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -191,12 +186,10 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||
@@ -205,12 +198,9 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -218,29 +208,24 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -254,11 +239,6 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200430040329-4b814e061378/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/runfn"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -208,10 +208,10 @@ data: {}
|
||||
return []*yaml.RNode{rc}, nil
|
||||
}
|
||||
|
||||
func toStorageMounts(mounts []string) []filters.StorageMount {
|
||||
var sms []filters.StorageMount
|
||||
func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
|
||||
var sms []runtimeutil.StorageMount
|
||||
for _, mount := range mounts {
|
||||
sms = append(sms, filters.StringToStorageMount(mount))
|
||||
sms = append(sms, runtimeutil.StringToStorageMount(mount))
|
||||
}
|
||||
return sms
|
||||
}
|
||||
|
||||
202
kyaml/fn/runtime/container/container.go
Normal file
202
kyaml/fn/runtime/container/container.go
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
runtimeexec "sigs.k8s.io/kustomize/kyaml/fn/runtime/exec"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Filter filters Resources using a container image.
|
||||
// The container must start a process that reads the list of
|
||||
// input Resources from stdin, reads the Configuration from the env
|
||||
// API_CONFIG, and writes the filtered Resources to stdout.
|
||||
// If there is a error or validation failure, the process must exit
|
||||
// non-zero.
|
||||
// The full set of environment variables from the parent process
|
||||
// are passed to the container.
|
||||
//
|
||||
// Function Scoping:
|
||||
// Filter applies the function only to Resources to which it is scoped.
|
||||
//
|
||||
// Resources are scoped to a function if any of the following are true:
|
||||
// - the Resource were read from the same directory as the function config
|
||||
// - the Resource were read from a subdirectory of the function config directory
|
||||
// - the function config is in a directory named "functions" and
|
||||
// they were read from a subdirectory of "functions" parent
|
||||
// - the function config doesn't have a path annotation (considered globally scoped)
|
||||
// - the Filter has GlobalScope == true
|
||||
//
|
||||
// In Scope Examples:
|
||||
//
|
||||
// Example 1: deployment.yaml and service.yaml in function.yaml scope
|
||||
// same directory as the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml in function.yaml scope
|
||||
// subdirectory of the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 3: apps/deployment.yaml and apps/service.yaml in functions/function.yaml scope
|
||||
// function config is in a directory named "functions"
|
||||
// .
|
||||
// ├── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Out of Scope Examples:
|
||||
//
|
||||
// Example 1: apps/deployment.yaml and apps/service.yaml NOT in stuff/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml NOT in stuff/functions/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Default Paths:
|
||||
// Resources emitted by functions will have default path applied as annotations
|
||||
// if none is present.
|
||||
// The default path will be the function-dir/ (or parent directory in the case of "functions")
|
||||
// + function-file-name/ + namespace/ + kind_name.yaml
|
||||
//
|
||||
// Example 1: Given a function in fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 2: Given a function in functions/fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── functions
|
||||
// │ └── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 3: Given a function in fn.yaml that produces a Deployment name foo, namespace baz and a Service named bar namespace baz
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// └── baz
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
type Filter struct {
|
||||
|
||||
// Image is the container image to use to create a container.
|
||||
Image string `yaml:"image,omitempty"`
|
||||
|
||||
// Network is the container network to use.
|
||||
Network string `yaml:"network,omitempty"`
|
||||
|
||||
// StorageMounts is a list of storage options that the container will have mounted.
|
||||
StorageMounts []runtimeutil.StorageMount `yaml:"mounts,omitempty"`
|
||||
|
||||
Exec runtimeexec.Filter
|
||||
}
|
||||
|
||||
func (c Filter) String() string {
|
||||
if c.Exec.DeferFailure {
|
||||
return fmt.Sprintf("%s deferFailure: %v", c.Image, c.Exec.DeferFailure)
|
||||
}
|
||||
return c.Image
|
||||
}
|
||||
func (c Filter) GetExit() error {
|
||||
return c.Exec.GetExit()
|
||||
}
|
||||
|
||||
func (c *Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
c.setupExec()
|
||||
return c.Exec.Filter(nodes)
|
||||
}
|
||||
|
||||
func (c *Filter) setupExec() {
|
||||
// don't init 2x
|
||||
if c.Exec.Path != "" {
|
||||
return
|
||||
}
|
||||
|
||||
path, args := c.getCommand()
|
||||
c.Exec.Path = path
|
||||
c.Exec.Args = args
|
||||
}
|
||||
|
||||
// getArgs returns the command + args to run to spawn the container
|
||||
func (c *Filter) getCommand() (string, []string) {
|
||||
// run the container using docker. this is simpler than using the docker
|
||||
// libraries, and ensures things like auth work the same as if the container
|
||||
// was run from the cli.
|
||||
|
||||
network := "none"
|
||||
if c.Network != "" {
|
||||
network = c.Network
|
||||
}
|
||||
|
||||
args := []string{"run",
|
||||
"--rm", // delete the container afterward
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR", // attach stdin, stdout, stderr
|
||||
"--network", network,
|
||||
|
||||
// added security options
|
||||
"--user", "nobody", // run as nobody
|
||||
"--security-opt=no-new-privileges", // don't allow the user to escalate privileges
|
||||
// note: don't make fs readonly because things like heredoc rely on writing tmp files
|
||||
}
|
||||
|
||||
// TODO(joncwong): Allow StorageMount fields to have default values.
|
||||
for _, storageMount := range c.StorageMounts {
|
||||
args = append(args, "--mount", storageMount.String())
|
||||
}
|
||||
|
||||
os.Setenv("LOG_TO_STDERR", "true")
|
||||
os.Setenv("STRUCTURED_RESULTS", "true")
|
||||
|
||||
// export the local environment vars to the container
|
||||
for _, pair := range os.Environ() {
|
||||
args = append(args, "-e", strings.Split(pair, "=")[0])
|
||||
}
|
||||
a := append(args, c.Image)
|
||||
|
||||
return "docker", a
|
||||
}
|
||||
203
kyaml/fn/runtime/container/container_test.go
Normal file
203
kyaml/fn/runtime/container/container_test.go
Normal file
@@ -0,0 +1,203 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
func TestFilter_setupExec(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
functionConfig string
|
||||
expectedArgs []string
|
||||
instance Filter
|
||||
}{
|
||||
{
|
||||
name: "command",
|
||||
functionConfig: `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
`,
|
||||
expectedArgs: []string{
|
||||
"run",
|
||||
"--rm",
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR",
|
||||
"--network", "none",
|
||||
"--user", "nobody",
|
||||
"--security-opt=no-new-privileges",
|
||||
},
|
||||
instance: Filter{Image: "example.com:version"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "network",
|
||||
functionConfig: `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
`,
|
||||
expectedArgs: []string{
|
||||
"run",
|
||||
"--rm",
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR",
|
||||
"--network", "test-1",
|
||||
"--user", "nobody",
|
||||
"--security-opt=no-new-privileges",
|
||||
},
|
||||
instance: Filter{Image: "example.com:version", Network: "test-1"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "storage_mounts",
|
||||
functionConfig: `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
`,
|
||||
expectedArgs: []string{
|
||||
"run",
|
||||
"--rm",
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR",
|
||||
"--network", "none",
|
||||
"--user", "nobody",
|
||||
"--security-opt=no-new-privileges",
|
||||
"--mount", fmt.Sprintf("type=%s,src=%s,dst=%s:ro", "bind", "/mount/path", "/local/"),
|
||||
"--mount", fmt.Sprintf("type=%s,src=%s,dst=%s:ro", "volume", "myvol", "/local/"),
|
||||
"--mount", fmt.Sprintf("type=%s,src=%s,dst=%s:ro", "tmpfs", "", "/local/"),
|
||||
},
|
||||
instance: Filter{
|
||||
Image: "example.com:version",
|
||||
StorageMounts: []runtimeutil.StorageMount{
|
||||
{MountType: "bind", Src: "/mount/path", DstPath: "/local/"},
|
||||
{MountType: "volume", Src: "myvol", DstPath: "/local/"},
|
||||
{MountType: "tmpfs", Src: "", DstPath: "/local/"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
tt := tests[i]
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg, err := yaml.Parse(tt.functionConfig)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
tt.instance.Exec.FunctionConfig = cfg
|
||||
|
||||
os.Setenv("KYAML_TEST", "FOO")
|
||||
tt.instance.setupExec()
|
||||
|
||||
// configure expected env
|
||||
for _, e := range os.Environ() {
|
||||
// the process env
|
||||
tt.expectedArgs = append(tt.expectedArgs, "-e", strings.Split(e, "=")[0])
|
||||
}
|
||||
tt.expectedArgs = append(tt.expectedArgs, tt.instance.Image)
|
||||
|
||||
if !assert.Equal(t, "docker", tt.instance.Exec.Path) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t, tt.expectedArgs, tt.instance.Exec.Args) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter_Filter(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
`)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
instance := Filter{}
|
||||
instance.Exec.FunctionConfig = cfg
|
||||
instance.Exec.Path = "sed"
|
||||
instance.Exec.Args = []string{"s/Deployment/StatefulSet/g"}
|
||||
output, err := instance.Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(output)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
config.kubernetes.io/path: 'service_service-foo.yaml'
|
||||
`, b.String()) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
func TestFilter_String(t *testing.T) {
|
||||
instance := Filter{Image: "foo"}
|
||||
if !assert.Equal(t, "foo", instance.String()) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
instance.Exec.DeferFailure = true
|
||||
if !assert.Equal(t, "foo deferFailure: true", instance.String()) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter_ExitCode(t *testing.T) {
|
||||
instance := Filter{}
|
||||
instance.Exec.Path = "/not/real/command"
|
||||
instance.Exec.DeferFailure = true
|
||||
_, err := instance.Filter(nil)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.EqualError(t, instance.GetExit(), "fork/exec /not/real/command: no such file or directory") {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filters
|
||||
package runtimeutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -72,6 +75,10 @@ type StorageMount struct {
|
||||
DstPath string `json:"dst,omitempty" yaml:"dst,omitempty"`
|
||||
}
|
||||
|
||||
func (s *StorageMount) String() string {
|
||||
return fmt.Sprintf("type=%s,src=%s,dst=%s:ro", s.MountType, s.Src, s.DstPath)
|
||||
}
|
||||
|
||||
// GetFunctionSpec returns the FunctionSpec for a resource. Returns
|
||||
// nil if the resource does not have a FunctionSpec.
|
||||
//
|
||||
@@ -119,3 +126,52 @@ func getFunctionSpecFromAnnotation(n *yaml.RNode, meta yaml.ResourceMeta) *Funct
|
||||
_ = yaml.Unmarshal([]byte(s), &fs)
|
||||
return &fs
|
||||
}
|
||||
|
||||
func StringToStorageMount(s string) StorageMount {
|
||||
m := make(map[string]string)
|
||||
options := strings.Split(s, ",")
|
||||
for _, option := range options {
|
||||
keyVal := strings.SplitN(option, "=", 2)
|
||||
m[keyVal[0]] = keyVal[1]
|
||||
}
|
||||
var sm StorageMount
|
||||
for key, value := range m {
|
||||
switch {
|
||||
case key == "type":
|
||||
sm.MountType = value
|
||||
case key == "src":
|
||||
sm.Src = value
|
||||
case key == "dst":
|
||||
sm.DstPath = value
|
||||
}
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
// IsReconcilerFilter filters Resources based on whether or not they are Reconciler Resource.
|
||||
// Resources with an apiVersion starting with '*.gcr.io', 'gcr.io' or 'docker.io' are considered
|
||||
// Reconciler Resources.
|
||||
type IsReconcilerFilter struct {
|
||||
// ExcludeReconcilers if set to true, then Reconcilers will be excluded -- e.g.
|
||||
// Resources with a reconcile container through the apiVersion (gcr.io prefix) or
|
||||
// through the annotations
|
||||
ExcludeReconcilers bool `yaml:"excludeReconcilers,omitempty"`
|
||||
|
||||
// IncludeNonReconcilers if set to true, the NonReconciler will be included.
|
||||
IncludeNonReconcilers bool `yaml:"includeNonReconcilers,omitempty"`
|
||||
}
|
||||
|
||||
// Filter implements kio.Filter
|
||||
func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
var out []*yaml.RNode
|
||||
for i := range inputs {
|
||||
isFnResource := GetFunctionSpec(inputs[i]) != nil
|
||||
if isFnResource && !c.ExcludeReconcilers {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
if !isFnResource && c.IncludeNonReconcilers {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -996,3 +996,272 @@ metadata:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetFunction(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
resource string
|
||||
expectedFn string
|
||||
missingFn bool
|
||||
}{
|
||||
|
||||
// fn annotation
|
||||
{
|
||||
name: "fn annotation",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "storage mounts json style",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
mounts: [ {type: bind, src: /mount/path, dst: /local/}, {src: myvol, dst: /local/, type: volume}, {dst: /local/, type: tmpfs} ]
|
||||
`,
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
mounts:
|
||||
- type: bind
|
||||
src: /mount/path
|
||||
dst: /local/
|
||||
- type: volume
|
||||
src: myvol
|
||||
dst: /local/
|
||||
- type: tmpfs
|
||||
dst: /local/
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "storage mounts yaml style",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
mounts:
|
||||
- src: /mount/path
|
||||
type: bind
|
||||
dst: /local/
|
||||
- dst: /local/
|
||||
src: myvol
|
||||
type: volume
|
||||
- type: tmpfs
|
||||
dst: /local/
|
||||
`,
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
mounts:
|
||||
- type: bind
|
||||
src: /mount/path
|
||||
dst: /local/
|
||||
- type: volume
|
||||
src: myvol
|
||||
dst: /local/
|
||||
- type: tmpfs
|
||||
dst: /local/
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "network",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
network:
|
||||
required: true
|
||||
`,
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
network:
|
||||
required: true
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "path",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
path: foo
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
// path should be erased
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "network",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |-
|
||||
network: foo
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
// network should be erased
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
},
|
||||
|
||||
// legacy fn style
|
||||
{name: "legacy fn meta",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
configFn:
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
expectedFn: `
|
||||
container:
|
||||
image: foo:v1.0.0
|
||||
`,
|
||||
},
|
||||
|
||||
// no fn
|
||||
{name: "no fn",
|
||||
resource: `
|
||||
apiVersion: v1beta1
|
||||
kind: Example
|
||||
metadata:
|
||||
annotations: {}
|
||||
`,
|
||||
missingFn: true,
|
||||
},
|
||||
|
||||
// test network, etc...
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
tt := tests[i]
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resource := yaml.MustParse(tt.resource)
|
||||
fn := GetFunctionSpec(resource)
|
||||
if tt.missingFn {
|
||||
if !assert.Nil(t, fn) {
|
||||
t.FailNow()
|
||||
}
|
||||
} else {
|
||||
b, err := yaml.Marshal(fn)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tt.expectedFn),
|
||||
strings.TrimSpace(string(b))) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetContainerNetworkRequired(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
required bool
|
||||
}{
|
||||
{
|
||||
input: `apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo
|
||||
configFn:
|
||||
container:
|
||||
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||
network:
|
||||
required: true
|
||||
`,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
input: `apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo
|
||||
configFn:
|
||||
container:
|
||||
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||
network:
|
||||
required: false
|
||||
`,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
|
||||
input: `apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo
|
||||
configFn:
|
||||
container:
|
||||
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||
`,
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
input: `apiVersion: v1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
container:
|
||||
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
|
||||
network:
|
||||
required: true
|
||||
`,
|
||||
required: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
cfg, err := yaml.Parse(tc.input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
fn := GetFunctionSpec(cfg)
|
||||
assert.Equal(t, tc.required, fn.Container.Network.Required)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// ContainerFilter filters Resources using a container image.
|
||||
// The container must start a process that reads the list of
|
||||
// input Resources from stdin, reads the Configuration from the env
|
||||
// API_CONFIG, and writes the filtered Resources to stdout.
|
||||
// If there is a error or validation failure, the process must exit
|
||||
// non-zero.
|
||||
// The full set of environment variables from the parent process
|
||||
// are passed to the container.
|
||||
//
|
||||
// Function Scoping:
|
||||
// ContainerFilter applies the function only to Resources to which it is scoped.
|
||||
//
|
||||
// Resources are scoped to a function if any of the following are true:
|
||||
// - the Resource were read from the same directory as the function config
|
||||
// - the Resource were read from a subdirectory of the function config directory
|
||||
// - the function config is in a directory named "functions" and
|
||||
// they were read from a subdirectory of "functions" parent
|
||||
// - the function config doesn't have a path annotation (considered globally scoped)
|
||||
// - the ContainerFilter has GlobalScope == true
|
||||
//
|
||||
// In Scope Examples:
|
||||
//
|
||||
// Example 1: deployment.yaml and service.yaml in function.yaml scope
|
||||
// same directory as the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml in function.yaml scope
|
||||
// subdirectory of the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 3: apps/deployment.yaml and apps/service.yaml in functions/function.yaml scope
|
||||
// function config is in a directory named "functions"
|
||||
// .
|
||||
// ├── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Out of Scope Examples:
|
||||
//
|
||||
// Example 1: apps/deployment.yaml and apps/service.yaml NOT in stuff/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml NOT in stuff/functions/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Default Paths:
|
||||
// Resources emitted by functions will have default path applied as annotations
|
||||
// if none is present.
|
||||
// The default path will be the function-dir/ (or parent directory in the case of "functions")
|
||||
// + function-file-name/ + namespace/ + kind_name.yaml
|
||||
//
|
||||
// Example 1: Given a function in fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 2: Given a function in functions/fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── functions
|
||||
// │ └── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 3: Given a function in fn.yaml that produces a Deployment name foo, namespace baz and a Service named bar namespace baz
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// └── baz
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
type ContainerFilter struct {
|
||||
|
||||
// Image is the container image to use to create a container.
|
||||
Image string `yaml:"image,omitempty"`
|
||||
|
||||
// Network is the container network to use.
|
||||
Network string `yaml:"network,omitempty"`
|
||||
|
||||
// StorageMounts is a list of storage options that the container will have mounted.
|
||||
StorageMounts []StorageMount `yaml:"mounts,omitempty"`
|
||||
|
||||
// Config is the API configuration for the container and passed through the
|
||||
// API_CONFIG env var to the container.
|
||||
// Typically a Kubernetes style Resource Config.
|
||||
Config *yaml.RNode `yaml:"config,omitempty"`
|
||||
|
||||
// GlobalScope will cause the function to be run against all input
|
||||
// nodes instead of only nodes scoped under the function.
|
||||
GlobalScope bool
|
||||
|
||||
ResultsFile string
|
||||
|
||||
Results *yaml.RNode
|
||||
|
||||
DeferFailure bool
|
||||
|
||||
Exit error
|
||||
|
||||
// SetFlowStyleForConfig sets the style for config to Flow when serializing it
|
||||
SetFlowStyleForConfig bool
|
||||
|
||||
// args may be specified by tests to override how a container is spawned
|
||||
args []string
|
||||
|
||||
checkInput func(string)
|
||||
}
|
||||
|
||||
func (c ContainerFilter) GetExit() error {
|
||||
return c.Exit
|
||||
}
|
||||
|
||||
type DeferFailureFunction interface {
|
||||
GetExit() error
|
||||
}
|
||||
|
||||
func (c ContainerFilter) String() string {
|
||||
if c.DeferFailure {
|
||||
return fmt.Sprintf("%s deferFailure: %v", c.Image, c.DeferFailure)
|
||||
}
|
||||
return c.Image
|
||||
}
|
||||
|
||||
func (s *StorageMount) String() string {
|
||||
return fmt.Sprintf("type=%s,src=%s,dst=%s:ro", s.MountType, s.Src, s.DstPath)
|
||||
}
|
||||
|
||||
func StringToStorageMount(s string) StorageMount {
|
||||
m := make(map[string]string)
|
||||
options := strings.Split(s, ",")
|
||||
for _, option := range options {
|
||||
keyVal := strings.SplitN(option, "=", 2)
|
||||
m[keyVal[0]] = keyVal[1]
|
||||
}
|
||||
var sm StorageMount
|
||||
for key, value := range m {
|
||||
switch {
|
||||
case key == "type":
|
||||
sm.MountType = value
|
||||
case key == "src":
|
||||
sm.Src = value
|
||||
case key == "dst":
|
||||
sm.DstPath = value
|
||||
}
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
// functionsDirectoryName is keyword directory name for functions scoped 1 directory higher
|
||||
const functionsDirectoryName = "functions"
|
||||
|
||||
// getFunctionScope returns the path of the directory containing the function config,
|
||||
// or its parent directory if the base directory is named "functions"
|
||||
func (c *ContainerFilter) getFunctionScope() (string, error) {
|
||||
m, err := c.Config.GetMeta()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err)
|
||||
}
|
||||
p, found := m.Annotations[kioutil.PathAnnotation]
|
||||
if !found {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
functionDir := path.Clean(path.Dir(p))
|
||||
|
||||
if path.Base(functionDir) == functionsDirectoryName {
|
||||
// the scope of functions in a directory called "functions" is 1 level higher
|
||||
// this is similar to how the golang "internal" directory scoping works
|
||||
functionDir = path.Dir(functionDir)
|
||||
}
|
||||
return functionDir, nil
|
||||
}
|
||||
|
||||
// scope partitions the input nodes into 2 slices. The first slice contains only Resources
|
||||
// which are scoped under dir, and the second slice contains the Resources which are not.
|
||||
func (c *ContainerFilter) scope(dir string, nodes []*yaml.RNode) ([]*yaml.RNode, []*yaml.RNode, error) {
|
||||
// scope container filtered Resources to Resources under that directory
|
||||
var input, saved []*yaml.RNode
|
||||
if c.GlobalScope {
|
||||
return nodes, nil, nil
|
||||
}
|
||||
|
||||
// global function
|
||||
if dir == "" || dir == "." {
|
||||
return nodes, nil, nil
|
||||
}
|
||||
|
||||
// identify Resources read from directories under the function configuration
|
||||
for i := range nodes {
|
||||
m, err := nodes[i].GetMeta()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p, found := m.Annotations[kioutil.PathAnnotation]
|
||||
if !found {
|
||||
// this Resource isn't scoped under the function -- don't know where it came from
|
||||
// consider it out of scope
|
||||
saved = append(saved, nodes[i])
|
||||
continue
|
||||
}
|
||||
|
||||
resourceDir := path.Clean(path.Dir(p))
|
||||
if path.Base(resourceDir) == functionsDirectoryName {
|
||||
// Functions in the `functions` directory are scoped to
|
||||
// themselves, and should see themselves as input
|
||||
resourceDir = path.Dir(resourceDir)
|
||||
}
|
||||
if !strings.HasPrefix(resourceDir, dir) {
|
||||
// this Resource doesn't fall under the function scope if it
|
||||
// isn't in a subdirectory of where the function lives
|
||||
saved = append(saved, nodes[i])
|
||||
continue
|
||||
}
|
||||
|
||||
// this input is scoped under the function
|
||||
input = append(input, nodes[i])
|
||||
}
|
||||
|
||||
return input, saved, nil
|
||||
}
|
||||
|
||||
// GrepFilter implements kio.GrepFilter
|
||||
func (c *ContainerFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
// get the command to filter the Resources
|
||||
cmd := c.getCommand()
|
||||
|
||||
in := &bytes.Buffer{}
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
// only process Resources scoped to this function, save the others
|
||||
functionDir, err := c.getFunctionScope()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input, saved, err := c.scope(functionDir, nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// write the input
|
||||
err = kio.ByteWriter{
|
||||
WrappingAPIVersion: kio.ResourceListAPIVersion,
|
||||
WrappingKind: kio.ResourceListKind,
|
||||
Writer: in,
|
||||
KeepReaderAnnotations: true,
|
||||
FunctionConfig: c.Config}.Write(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// capture the command stdout for the return value
|
||||
r := &kio.ByteReader{Reader: out}
|
||||
|
||||
// do the filtering
|
||||
if c.checkInput != nil {
|
||||
c.checkInput(in.String())
|
||||
}
|
||||
cmd.Stdin = in
|
||||
cmd.Stdout = out
|
||||
|
||||
// don't exit immediately if the function fails -- write out the validation
|
||||
c.Exit = cmd.Run()
|
||||
|
||||
output, err := r.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.doResults(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Exit != nil && !c.DeferFailure {
|
||||
return append(output, saved...), c.Exit
|
||||
}
|
||||
|
||||
// annotate any generated Resources with a path and index if they don't already have one
|
||||
if err := kioutil.DefaultPathAnnotation(functionDir, output); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// emit both the Resources output from the function, and the out-of-scope Resources
|
||||
// which were not provided to the function
|
||||
return append(output, saved...), nil
|
||||
}
|
||||
|
||||
func (c *ContainerFilter) doResults(r *kio.ByteReader) error {
|
||||
// Write the results to a file if configured to do so
|
||||
if c.ResultsFile != "" && r.Results != nil {
|
||||
results, err := r.Results.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(c.ResultsFile, []byte(results), 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if r.Results != nil {
|
||||
c.Results = r.Results
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getArgs returns the command + args to run to spawn the container
|
||||
func (c *ContainerFilter) getArgs() []string {
|
||||
// run the container using docker. this is simpler than using the docker
|
||||
// libraries, and ensures things like auth work the same as if the container
|
||||
// was run from the cli.
|
||||
|
||||
network := "none"
|
||||
if c.Network != "" {
|
||||
network = c.Network
|
||||
}
|
||||
|
||||
args := []string{"docker", "run",
|
||||
"--rm", // delete the container afterward
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR", // attach stdin, stdout, stderr
|
||||
|
||||
// added security options
|
||||
"--network", network,
|
||||
"--user", "nobody", // run as nobody
|
||||
// don't make fs readonly because things like heredoc rely on writing tmp files
|
||||
"--security-opt=no-new-privileges", // don't allow the user to escalate privileges
|
||||
}
|
||||
|
||||
// TODO(joncwong): Allow StorageMount fields to have default values.
|
||||
for _, storageMount := range c.StorageMounts {
|
||||
args = append(args, "--mount", storageMount.String())
|
||||
}
|
||||
|
||||
// tell functions to write error messages to stderr as well as results
|
||||
os.Setenv("LOG_TO_STDERR", "true")
|
||||
os.Setenv("STRUCTURED_RESULTS", "true")
|
||||
|
||||
// export the local environment vars to the container
|
||||
for _, pair := range os.Environ() {
|
||||
tokens := strings.Split(pair, "=")
|
||||
if tokens[0] == "" {
|
||||
continue
|
||||
}
|
||||
args = append(args, "-e", tokens[0])
|
||||
}
|
||||
return append(args, c.Image)
|
||||
}
|
||||
|
||||
// getCommand returns a command which will apply the Filter using the container image
|
||||
func (c *ContainerFilter) getCommand() *exec.Cmd {
|
||||
if c.SetFlowStyleForConfig {
|
||||
c.Config.YNode().Style = yaml.FlowStyle
|
||||
}
|
||||
|
||||
if len(c.args) == 0 {
|
||||
c.args = c.getArgs()
|
||||
}
|
||||
|
||||
cmd := exec.Command(c.args[0], c.args[1:]...)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
// set stderr for err messaging
|
||||
return cmd
|
||||
}
|
||||
|
||||
// IsReconcilerFilter filters Resources based on whether or not they are Reconciler Resource.
|
||||
// Resources with an apiVersion starting with '*.gcr.io', 'gcr.io' or 'docker.io' are considered
|
||||
// Reconciler Resources.
|
||||
type IsReconcilerFilter struct {
|
||||
// ExcludeReconcilers if set to true, then Reconcilers will be excluded -- e.g.
|
||||
// Resources with a reconcile container through the apiVersion (gcr.io prefix) or
|
||||
// through the annotations
|
||||
ExcludeReconcilers bool `yaml:"excludeReconcilers,omitempty"`
|
||||
|
||||
// IncludeNonReconcilers if set to true, the NonReconciler will be included.
|
||||
IncludeNonReconcilers bool `yaml:"includeNonReconcilers,omitempty"`
|
||||
}
|
||||
|
||||
// Filter implements kio.Filter
|
||||
func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
var out []*yaml.RNode
|
||||
for i := range inputs {
|
||||
isFnResource := GetFunctionSpec(inputs[i]) != nil
|
||||
if isFnResource && !c.ExcludeReconcilers {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
if !isFnResource && c.IncludeNonReconcilers {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,9 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/container"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/starlark"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
// RunFns runs the set of configuration functions in a local directory against
|
||||
// the Resources in that directory
|
||||
type RunFns struct {
|
||||
StorageMounts []filters.StorageMount
|
||||
StorageMounts []runtimeutil.StorageMount
|
||||
|
||||
// Path is the path to the directory containing functions
|
||||
Path string
|
||||
@@ -75,7 +76,7 @@ type RunFns struct {
|
||||
// functionFilterProvider provides a filter to perform the function.
|
||||
// this is a variable so it can be mocked in tests
|
||||
functionFilterProvider func(
|
||||
filter filters.FunctionSpec, api *yaml.RNode) (kio.Filter, error)
|
||||
filter runtimeutil.FunctionSpec, api *yaml.RNode) (kio.Filter, error)
|
||||
}
|
||||
|
||||
// Execute runs the command
|
||||
@@ -173,7 +174,7 @@ func (r RunFns) runFunctions(
|
||||
// check for deferred function errors
|
||||
var errs []string
|
||||
for i := range fltrs {
|
||||
cf, ok := fltrs[i].(filters.DeferFailureFunction)
|
||||
cf, ok := fltrs[i].(runtimeutil.DeferFailureFunction)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -196,7 +197,7 @@ func (r RunFns) getFunctionsFromInput(nodes []*yaml.RNode) ([]kio.Filter, error)
|
||||
buff := &kio.PackageBuffer{}
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{&kio.PackageBuffer{Nodes: nodes}},
|
||||
Filters: []kio.Filter{&filters.IsReconcilerFilter{}},
|
||||
Filters: []kio.Filter{&runtimeutil.IsReconcilerFilter{}},
|
||||
Outputs: []kio.Writer{buff},
|
||||
}.Execute()
|
||||
if err != nil {
|
||||
@@ -235,7 +236,7 @@ func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) (
|
||||
var fltrs []kio.Filter
|
||||
for i := range fns {
|
||||
api := fns[i]
|
||||
spec := filters.GetFunctionSpec(api)
|
||||
spec := runtimeutil.GetFunctionSpec(api)
|
||||
if spec.Container.Network.Required {
|
||||
if !r.Network {
|
||||
// TODO(eddiezane): Provide error info about which function needs the network
|
||||
@@ -251,9 +252,9 @@ func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) (
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
cf, ok := c.(*filters.ContainerFilter)
|
||||
cf, ok := c.(*container.Filter)
|
||||
if global && ok {
|
||||
cf.GlobalScope = true
|
||||
cf.Exec.GlobalScope = true
|
||||
}
|
||||
fltrs = append(fltrs, c)
|
||||
}
|
||||
@@ -331,7 +332,7 @@ func (r *RunFns) init() {
|
||||
}
|
||||
|
||||
// ffp provides function filters
|
||||
func (r *RunFns) ffp(spec filters.FunctionSpec, api *yaml.RNode) (kio.Filter, error) {
|
||||
func (r *RunFns) ffp(spec runtimeutil.FunctionSpec, api *yaml.RNode) (kio.Filter, error) {
|
||||
if !r.DisableContainers && spec.Container.Image != "" {
|
||||
var resultsFile string
|
||||
// TODO: Add a test for this behavior
|
||||
@@ -341,15 +342,17 @@ func (r *RunFns) ffp(spec filters.FunctionSpec, api *yaml.RNode) (kio.Filter, er
|
||||
"results-%v.yaml", r.resultsCount))
|
||||
atomic.AddUint32(&r.resultsCount, 1)
|
||||
}
|
||||
return &filters.ContainerFilter{
|
||||
|
||||
cf := &container.Filter{
|
||||
Image: spec.Container.Image,
|
||||
Config: api,
|
||||
Network: spec.Network,
|
||||
StorageMounts: r.StorageMounts,
|
||||
GlobalScope: r.GlobalScope,
|
||||
ResultsFile: resultsFile,
|
||||
DeferFailure: spec.DeferFailure,
|
||||
}, nil
|
||||
}
|
||||
cf.Exec.FunctionConfig = api
|
||||
cf.Exec.GlobalScope = r.GlobalScope
|
||||
cf.Exec.ResultsFile = resultsFile
|
||||
cf.Exec.DeferFailure = spec.DeferFailure
|
||||
return cf, nil
|
||||
}
|
||||
if r.EnableStarlark && spec.Starlark.Path != "" {
|
||||
// the script path is relative to the function config file
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/kyaml/copyutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/container"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/filters"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
@@ -48,8 +50,8 @@ func TestRunFns_init(t *testing.T) {
|
||||
api, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind:
|
||||
`)
|
||||
spec := filters.FunctionSpec{
|
||||
Container: filters.ContainerSpec{
|
||||
spec := runtimeutil.FunctionSpec{
|
||||
Container: runtimeutil.ContainerSpec{
|
||||
Image: "example.com:version",
|
||||
},
|
||||
}
|
||||
@@ -57,7 +59,9 @@ kind:
|
||||
return
|
||||
}
|
||||
filter, _ := instance.functionFilterProvider(spec, api)
|
||||
assert.Equal(t, &filters.ContainerFilter{Image: "example.com:version", Config: api}, filter)
|
||||
cf := &container.Filter{Image: "example.com:version"}
|
||||
cf.Exec.FunctionConfig = api
|
||||
assert.Equal(t, cf, filter)
|
||||
}
|
||||
|
||||
func TestRunFns_Execute__initGlobalScope(t *testing.T) {
|
||||
@@ -76,8 +80,8 @@ kind:
|
||||
return
|
||||
}
|
||||
|
||||
spec := filters.FunctionSpec{
|
||||
Container: filters.ContainerSpec{
|
||||
spec := runtimeutil.FunctionSpec{
|
||||
Container: runtimeutil.ContainerSpec{
|
||||
Image: "example.com:version",
|
||||
},
|
||||
}
|
||||
@@ -85,8 +89,10 @@ kind:
|
||||
return
|
||||
}
|
||||
filter, _ := instance.functionFilterProvider(spec, api)
|
||||
assert.Equal(t, &filters.ContainerFilter{
|
||||
Image: "example.com:version", Config: api, GlobalScope: true}, filter)
|
||||
cf := &container.Filter{Image: "example.com:version"}
|
||||
cf.Exec.FunctionConfig = api
|
||||
cf.Exec.GlobalScope = true
|
||||
assert.Equal(t, cf, filter)
|
||||
}
|
||||
|
||||
func TestRunFns_Execute__initDefault(t *testing.T) {
|
||||
@@ -143,12 +149,12 @@ func TestRunFns_Execute__initDefault(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "explicit directories in mounts",
|
||||
instance: RunFns{StorageMounts: []filters.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}}},
|
||||
instance: RunFns{StorageMounts: []runtimeutil.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}}},
|
||||
expected: RunFns{
|
||||
Output: os.Stdout,
|
||||
Input: os.Stdin,
|
||||
NoFunctionsFromInput: getFalse(),
|
||||
StorageMounts: []filters.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}},
|
||||
StorageMounts: []runtimeutil.StorageMount{{MountType: "volume", Src: "myvol", DstPath: "/local/"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -751,7 +757,7 @@ replace: StatefulSet
|
||||
var fltrs []*TestFilter
|
||||
instance := RunFns{
|
||||
Path: dir,
|
||||
functionFilterProvider: func(f filters.FunctionSpec, node *yaml.RNode) (kio.Filter, error) {
|
||||
functionFilterProvider: func(f runtimeutil.FunctionSpec, node *yaml.RNode) (kio.Filter, error) {
|
||||
tf := &TestFilter{
|
||||
Exit: errors.Errorf("message: %s", f.Container.Image),
|
||||
}
|
||||
@@ -927,8 +933,8 @@ func setupTest(t *testing.T) string {
|
||||
// getFilterProvider fakes the creation of a filter, replacing the ContainerFiler with
|
||||
// a filter to s/kind: Deployment/kind: StatefulSet/g.
|
||||
// this can be used to simulate running a filter.
|
||||
func getFilterProvider(t *testing.T) func(filters.FunctionSpec, *yaml.RNode) (kio.Filter, error) {
|
||||
return func(f filters.FunctionSpec, node *yaml.RNode) (kio.Filter, error) {
|
||||
func getFilterProvider(t *testing.T) func(runtimeutil.FunctionSpec, *yaml.RNode) (kio.Filter, error) {
|
||||
return func(f runtimeutil.FunctionSpec, node *yaml.RNode) (kio.Filter, error) {
|
||||
// parse the filter from the input
|
||||
filter := yaml.YFilter{}
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
Reference in New Issue
Block a user