diff --git a/go.mod b/go.mod index 95db7687f..0d8b7d91a 100644 --- a/go.mod +++ b/go.mod @@ -20,12 +20,20 @@ require ( require ( github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.24.1 + github.com/spf13/afero v1.6.0 + sigs.k8s.io/yaml v1.3.0 +) + +require ( github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -49,6 +57,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nxadm/tail v1.4.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect @@ -78,6 +87,7 @@ require ( google.golang.org/grpc v1.49.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiserver v0.26.1 // indirect @@ -88,5 +98,4 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index e108513ed..263bbdc80 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,10 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-bindata/go-bindata/v3 v3.1.3 h1:F0nVttLC3ws0ojc7p60veTurcOm//D4QBODNM7EGrCI= @@ -116,6 +120,7 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -191,6 +196,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QG github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -214,6 +220,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -242,11 +249,22 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -284,6 +302,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -335,6 +355,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -373,6 +394,7 @@ golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -395,6 +417,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -427,6 +450,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -437,8 +461,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -459,6 +486,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -468,6 +496,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -531,6 +560,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= @@ -638,8 +668,11 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/manifests/bundle.go b/pkg/manifests/bundle.go index 9be294a35..37639f8f3 100644 --- a/pkg/manifests/bundle.go +++ b/pkg/manifests/bundle.go @@ -5,6 +5,7 @@ import ( apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "github.com/operator-framework/api/pkg/metadata" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" ) @@ -18,7 +19,7 @@ type Bundle struct { CSV *operatorsv1alpha1.ClusterServiceVersion V1beta1CRDs []*apiextensionsv1beta1.CustomResourceDefinition V1CRDs []*apiextensionsv1.CustomResourceDefinition - Dependencies []*Dependency + Dependencies []*metadata.Dependency // CompressedSize stores the gzip size of the bundle CompressedSize int64 // Size stores the size of the bundle diff --git a/pkg/manifests/bundleloader.go b/pkg/manifests/bundleloader.go index 94f14a22a..c6af97205 100644 --- a/pkg/manifests/bundleloader.go +++ b/pkg/manifests/bundleloader.go @@ -14,6 +14,7 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" "github.com/operator-framework/api/pkg/encoding" + "github.com/operator-framework/api/pkg/metadata" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" ) @@ -22,7 +23,7 @@ type bundleLoader struct { dir string bundle *Bundle foundCSV bool - annotationsFile AnnotationsFile + annotationsFile metadata.AnnotationsFile } func NewBundleLoader(dir string) bundleLoader { @@ -63,8 +64,8 @@ func (b *bundleLoader) addChannelsFromAnnotationsFile() { if len(channels) > 0 && len(b.bundle.Channels) == 0 { b.bundle.Channels = channels } - if len(b.annotationsFile.Annotations.DefaultChannelName) > 0 && len(b.bundle.DefaultChannel) == 0 { - b.bundle.DefaultChannel = b.annotationsFile.Annotations.DefaultChannelName + if len(b.annotationsFile.Annotations.DefaultChannel) > 0 && len(b.bundle.DefaultChannel) == 0 { + b.bundle.DefaultChannel = b.annotationsFile.Annotations.DefaultChannel } } @@ -129,7 +130,7 @@ func (b *bundleLoader) LoadBundleWalkFunc(path string, f os.FileInfo, err error) return nil } - annotationsFile := AnnotationsFile{} + annotationsFile := metadata.AnnotationsFile{} if strings.HasPrefix(f.Name(), "annotations") { annFile, err := os.ReadFile(path) if err != nil { diff --git a/pkg/manifests/bundlemeta.go b/pkg/manifests/bundlemeta.go deleted file mode 100644 index da2403e3d..000000000 --- a/pkg/manifests/bundlemeta.go +++ /dev/null @@ -1,37 +0,0 @@ -package manifests - -// AnnotationsFile holds annotation information about a bundle -type AnnotationsFile struct { - // annotations is a list of annotations for a given bundle - Annotations Annotations `json:"annotations" yaml:"annotations"` -} - -// Annotations is a list of annotations for a given bundle -type Annotations struct { - // PackageName is the name of the overall package, ala `etcd`. - PackageName string `json:"operators.operatorframework.io.bundle.package.v1" yaml:"operators.operatorframework.io.bundle.package.v1"` - - // Channels are a comma separated list of the declared channels for the bundle, ala `stable` or `alpha`. - Channels string `json:"operators.operatorframework.io.bundle.channels.v1" yaml:"operators.operatorframework.io.bundle.channels.v1"` - - // DefaultChannelName is, if specified, the name of the default channel for the package. The - // default channel will be installed if no other channel is explicitly given. If the package - // has a single channel, then that channel is implicitly the default. - DefaultChannelName string `json:"operators.operatorframework.io.bundle.channel.default.v1" yaml:"operators.operatorframework.io.bundle.channel.default.v1"` -} - -// DependenciesFile holds dependency information about a bundle -type DependenciesFile struct { - // Dependencies is a list of dependencies for a given bundle - Dependencies []Dependency `json:"dependencies" yaml:"dependencies"` -} - -// Dependencies is a list of dependencies for a given bundle -type Dependency struct { - // The type of dependency. It can be `olm.package` for operator-version based - // dependency or `olm.gvk` for gvk based dependency. This field is required. - Type string `json:"type" yaml:"type"` - - // The value of the dependency (either GVKDependency or PackageDependency) - Value string `json:"value" yaml:"value"` -} diff --git a/pkg/metadata/directory.go b/pkg/metadata/directory.go new file mode 100644 index 000000000..1e371890c --- /dev/null +++ b/pkg/metadata/directory.go @@ -0,0 +1,76 @@ +package metadata + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/spf13/afero" +) + +// The bundle root-relative default annotations.yaml path. +var defaultRelPath = filepath.Join("metadata", "annotations.yaml") + +// FindAnnotations walks bundleRoot searching for bundle metadata in an annotations.yaml file, +// and returns this metadata and its path if found. If one is not found, an error is returned. +func FindAnnotations(bundleRoot string) (AnnotationsFile, string, error) { + return findAnnotations(afero.NewOsFs(), bundleRoot) +} + +func findAnnotations(fs afero.Fs, bundleRoot string) (AnnotationsFile, string, error) { + // Check the default path first, and return annotations if they were found or an error if that error + // is not because the path does not exist (it exists or there was an unmarshaling error). + annotationsPath := filepath.Join(bundleRoot, defaultRelPath) + af, err := readAnnotations(fs, annotationsPath) + if err != nil { + // Ignore this error, since the annotations might be in some other file. + log.Debug(err) + } else if !af.IsEmpty() { + return af, annotationsPath, nil + } + + // Annotations are not at the default path, so search recursively. + foundAnnotations := false + annotationsPath = "" + err = afero.Walk(fs, bundleRoot, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + // Skip if annotations were already found, or path is a directory or hidden file. + if foundAnnotations || info.IsDir() || strings.HasPrefix(path, ".") { + return nil + } + + annotationsPath = path + if af, err = readAnnotations(fs, path); err != nil { + // We don't want to stop early, so ignore this error and try other files. + log.Debug(err) + } else if !af.IsEmpty() { + foundAnnotations = true + } + return nil + }) + if err != nil { + return af, "", err + } + + if !foundAnnotations { + return af, "", fmt.Errorf("metadata not found in %s", bundleRoot) + } + + return af, annotationsPath, nil +} + +// readAnnotations attempts to read annotations from annotationsPath. +func readAnnotations(fs afero.Fs, annotationsPath string) (af AnnotationsFile, err error) { + b, err := afero.ReadFile(fs, annotationsPath) + if err != nil { + return af, err + } + if err = af.Unmarshal(b); err != nil { + return af, fmt.Errorf("error unmarshaling potential bundle metadata %s: %v", annotationsPath, err) + } + return af, nil +} diff --git a/pkg/metadata/directory_test.go b/pkg/metadata/directory_test.go new file mode 100644 index 000000000..a028651ef --- /dev/null +++ b/pkg/metadata/directory_test.go @@ -0,0 +1,169 @@ +package metadata + +import ( + "path/filepath" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/spf13/afero" +) + +var _ = Describe("Annotations", func() { + Describe("FindAnnotations", func() { + var ( + fs afero.Fs + err error + defaultPath = "/bundle/metadata/annotations.yaml" + ) + + Context("with valid annotations contents", func() { + var ( + annotationsFile AnnotationsFile + path, expPath string + ) + BeforeEach(func() { + fs = afero.NewMemMapFs() + }) + + // Location + It("finds registry metadata in the default location", func() { + expPath = defaultPath + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + It("finds registry metadata in the a custom file name", func() { + expPath = "/bundle/metadata/my-metadata.yaml" + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + It("finds registry metadata in a custom single-depth location", func() { + expPath = "/bundle/my-dir/my-metadata.yaml" + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + It("finds registry metadata in a custom multi-depth location", func() { + expPath = "/bundle/my-parent-dir/my-dir/annotations.yaml" + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + It("returns registry metadata from default path when metadata is also in another location", func() { + expPath = defaultPath + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + writeMetadataHelper(fs, "/bundle/other-metadata/annotations.yaml", annotationsStringValidNoRegLabels) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + It("returns registry metadata from the first path, when metadata is also in another location", func() { + expPath = "/bundle/custom1/annotations.yaml" + writeMetadataHelper(fs, expPath, annotationsStringValidV1) + writeMetadataHelper(fs, "/bundle/custom2/annotations.yaml", annotationsStringValidNoRegLabels) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1)) + }) + + // Format + It("finds non-registry metadata", func() { + expPath = defaultPath + writeMetadataHelper(fs, defaultPath, annotationsStringValidNoRegLabels) + annotationsFile, path, err = findAnnotations(fs, "/bundle") + Expect(err).To(BeNil()) + Expect(path).To(Equal(expPath)) + Expect(annotationsFile).To(BeEquivalentTo(annotationsValidNoRegLabels)) + }) + }) + + Context("with invalid annotations contents", func() { + BeforeEach(func() { + fs = afero.NewMemMapFs() + }) + + It("returns an error for no metadata file (YAML error)", func() { + writeMetadataHelper(fs, defaultPath, annotationsStringInvalidBadIndent) + _, _, err = findAnnotations(fs, "/bundle") + Expect(err).To(MatchError("metadata not found in /bundle")) + }) + It("returns an error for no metadata file (empty file)", func() { + writeMetadataHelper(fs, defaultPath, annotationsStringInvalidEmpty) + _, _, err = findAnnotations(fs, "/bundle") + Expect(err).To(MatchError("metadata not found in /bundle")) + }) + It("returns an error for no metadata file (invalid top-level key)", func() { + writeMetadataHelper(fs, defaultPath, annotationsStringInvalidTopKey) + _, _, err = findAnnotations(fs, "/bundle") + Expect(err).To(MatchError("metadata not found in /bundle")) + }) + It("returns an error for no labels in a metadata file", func() { + writeMetadataHelper(fs, defaultPath, annotationsStringInvalidNoLabels) + _, _, err = findAnnotations(fs, "/bundle") + Expect(err).To(MatchError("metadata not found in /bundle")) + }) + }) + }) + +}) + +func writeMetadataHelper(fs afero.Fs, path, contents string) { + ExpectWithOffset(1, fs.MkdirAll(filepath.Dir(path), 0755)).Should(Succeed()) + ExpectWithOffset(1, afero.WriteFile(fs, path, []byte(contents), 0666)).Should(Succeed()) +} + +var annotationsValidV1 = AnnotationsFile{ + Annotations: AnnotationsV1{ + MediaType: "registry+v1", + MetadataDir: "metadata/", + AnnotationsRaw: map[string]string{ + "foo": "bar", + }, + }, +} + +const annotationsStringValidV1 = `annotations: + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 + operators.operatorframework.io.bundle.metadata.v1: metadata/ + foo: bar +` + +var annotationsValidNoRegLabels = AnnotationsFile{ + Annotations: AnnotationsV1{ + AnnotationsRaw: map[string]string{ + "foo": "bar", + "baz": "buf", + }, + }, +} + +const annotationsStringValidNoRegLabels = `annotations: + foo: bar + baz: buf +` + +const annotationsStringInvalidBadIndent = `annotations: + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 +` + +const annotationsStringInvalidEmpty = `` + +const annotationsStringInvalidNoLabels = `annotations: +` + +const annotationsStringInvalidTopKey = `not-annotations: + operators.operatorframework.io.bundle.mediatype.v1: registry+v1 + operators.operatorframework.io.bundle.metadata.v1: metadata/ + foo: bar +` diff --git a/pkg/metadata/metadata_suite_test.go b/pkg/metadata/metadata_suite_test.go new file mode 100644 index 000000000..14b9f39f0 --- /dev/null +++ b/pkg/metadata/metadata_suite_test.go @@ -0,0 +1,13 @@ +package metadata + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestMetadata(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Metadata Suite") +} diff --git a/pkg/metadata/types.go b/pkg/metadata/types.go new file mode 100644 index 000000000..9fa092023 --- /dev/null +++ b/pkg/metadata/types.go @@ -0,0 +1,140 @@ +package metadata + +import ( + "reflect" + + "sigs.k8s.io/yaml" +) + +// AnnotationsFile holds annotation information about a bundle +type AnnotationsFile struct { + // Annotations is a set of annotations for a given bundle with both tagged and arbitrary fields. + // Tagged fields are versioned based on the type of Annotations. + Annotations AnnotationsV1 `json:"annotations" yaml:"annotations"` +} + +// annotationsFileInternal is used for (un)marshaling an AnnotationsFile, which +// contains both tagged and arbitrary fields. +type annotationsFileInternal struct { + Annotations map[string]string `json:"annotations"` +} + +func (af AnnotationsFile) Marshal() ([]byte, error) { + b, err := yaml.Marshal(af) + if err != nil { + return nil, err + } + + // Add arbitrary annotations to the set of all annotations in af. + annotations := make(map[string]string) + if err := yaml.Unmarshal(b, annotations); err != nil { + return nil, err + } + for label, value := range af.Annotations.AnnotationsRaw { + annotations[label] = value + } + + return yaml.Marshal(annotationsFileInternal{annotations}) +} + +func (af *AnnotationsFile) Unmarshal(b []byte) error { + if err := yaml.Unmarshal(b, af); err != nil { + return err + } + + // Add arbitrary annotations in b to the set of raw annotations in af, + // since the YAML unmarshaler cannot inherently do this. + raw := annotationsFileInternal{make(map[string]string)} + if err := yaml.Unmarshal(b, &raw); err != nil { + return err + } + for _, label := range af.Annotations.GetLabels() { + delete(raw.Annotations, label) + } + af.Annotations.AnnotationsRaw = make(map[string]string) + for label, value := range raw.Annotations { + af.Annotations.AnnotationsRaw[label] = value + } + + return nil +} + +// IsEmpty returns true if af is empty. +func (af AnnotationsFile) IsEmpty() bool { + // A non-empty AnnotationsRaw value means af is not the zero value. + if len(af.Annotations.AnnotationsRaw) != 0 { + return false + } + // Value.IsZero() returns true if the map was initialized, which isn't correct for our purposes. + af.Annotations.AnnotationsRaw = nil + return reflect.ValueOf(af).IsZero() +} + +// Bundle v1 labels. +const ( + MediaTypeLabelV1 = "operators.operatorframework.io.bundle.mediatype.v1" + ManifestsLabelV1 = "operators.operatorframework.io.bundle.manifests.v1" + MetadataLabelV1 = "operators.operatorframework.io.bundle.metadata.v1" + PackageLabelV1 = "operators.operatorframework.io.bundle.package.v1" + ChannelsLabelV1 = "operators.operatorframework.io.bundle.channels.v1" + DefaultChannelLabelV1 = "operators.operatorframework.io.bundle.channel.default.v1" +) + +// AnnotationsV1 is a set of v1 annotations for a given bundle. +type AnnotationsV1 struct { + // MediaType is this bundle's media type. Valid values are: + // - "registry+v1": operator-registry manifests. + // - "helm": Helm charts. + // - "plain": standard Kubernetes manifests. + MediaType string `json:"operators.operatorframework.io.bundle.mediatype.v1" yaml:"operators.operatorframework.io.bundle.mediatype.v1"` + + // ManifestsDir contains the relative manifests directory path. This path is relative + // to the parent directory of the metadata dir, i.e. filepath.Dir(MetadataDir). + ManifestsDir string `json:"operators.operatorframework.io.bundle.manifests.v1" yaml:"operators.operatorframework.io.bundle.manifests.v1"` + + // MetadataDir contains the relative metadata directory path. This path is relative + // to the bundle root directory, i.e. filepath.Dir(). + MetadataDir string `json:"operators.operatorframework.io.bundle.metadata.v1" yaml:"operators.operatorframework.io.bundle.metadata.v1"` + + // PackageName is the name of the overall package, ala `etcd`. + PackageName string `json:"operators.operatorframework.io.bundle.package.v1" yaml:"operators.operatorframework.io.bundle.package.v1"` + + // Channels are a comma separated list of the declared channels for the bundle, ala `stable` or `alpha`. + Channels string `json:"operators.operatorframework.io.bundle.channels.v1" yaml:"operators.operatorframework.io.bundle.channels.v1"` + + // DefaultChannel is, if specified, the name of the default channel for the package. The + // default channel will be installed if no other channel is explicitly given. If the package + // has a single channel, then that channel is implicitly the default. + DefaultChannel string `json:"operators.operatorframework.io.bundle.channel.default.v1" yaml:"operators.operatorframework.io.bundle.channel.default.v1"` + + // AnnotationsRaw contains all other annotations in an annotations file + // that do not have keys that match the above tags. + AnnotationsRaw map[string]string `json:"-" yaml:"-"` +} + +func (a AnnotationsV1) GetLabels() []string { + return []string{ + MediaTypeLabelV1, + ManifestsLabelV1, + MetadataLabelV1, + PackageLabelV1, + ChannelsLabelV1, + DefaultChannelLabelV1, + } +} + +// DependenciesFile holds dependency information about a bundle +type DependenciesFile struct { + // Dependencies is a list of dependencies for a given bundle + Dependencies []Dependency `json:"dependencies" yaml:"dependencies"` +} + +// Dependencies is a list of dependencies for a given bundle +type Dependency struct { + // The type of dependency. It can be `olm.package` for operator-version based + // dependency or `olm.gvk` for gvk based dependency. This field is required. + Type string `json:"type" yaml:"type"` + + // The value of the dependency (either GVKDependency or PackageDependency) + Value string `json:"value" yaml:"value"` +}