From a0c78850a5669b80803b13aa68a945cde4b2f7cb Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Sat, 10 Jul 2021 22:52:37 -0400 Subject: [PATCH 01/30] declcfg: improve and fix model tests to eliminate possibility of false negatives Signed-off-by: Joe Lanford Upstream-repository: operator-registry Upstream-commit: 95c5e3bca1ac3abb3bf00f6b7345ddbd047e1524 --- .../operator-registry/internal/model/model.go | 3 - .../internal/model/model_test.go | 130 +++++++++--------- .../operator-registry/internal/model/model.go | 3 - 3 files changed, 68 insertions(+), 68 deletions(-) diff --git a/staging/operator-registry/internal/model/model.go b/staging/operator-registry/internal/model/model.go index e0abf6fbf5..330ea84db1 100644 --- a/staging/operator-registry/internal/model/model.go +++ b/staging/operator-registry/internal/model/model.go @@ -269,9 +269,6 @@ type RelatedImage struct { func (i RelatedImage) Validate() error { result := newValidationError("invalid related image") - if i.Name == "" { - result.subErrors = append(result.subErrors, fmt.Errorf("name must be set")) - } if i.Image == "" { result.subErrors = append(result.subErrors, fmt.Errorf("image must be set")) } diff --git a/staging/operator-registry/internal/model/model_test.go b/staging/operator-registry/internal/model/model_test.go index 99a1799d05..7ff3cc34fb 100644 --- a/staging/operator-registry/internal/model/model_test.go +++ b/staging/operator-registry/internal/model/model_test.go @@ -97,7 +97,7 @@ func TestChannelHead(t *testing.T) { "anakin.v0.0.1": {Name: "anakin.v0.0.1", Replaces: "anakin.v0.0.3"}, "anakin.v0.0.3": head, }}, - assertion: require.Error, + assertion: hasError(`no channel head found in graph`), }, { name: "Error/MultipleChannelHeads", @@ -106,7 +106,7 @@ func TestChannelHead(t *testing.T) { "anakin.v0.0.3": head, "anakin.v0.0.4": {Name: "anakin.v0.0.4", Replaces: "anakin.v0.0.1"}, }}, - assertion: require.Error, + assertion: hasError(`multiple channel heads found in graph: anakin.v0.0.3, anakin.v0.0.4`), }, } for _, s := range specs { @@ -118,6 +118,32 @@ func TestChannelHead(t *testing.T) { } } +func hasError(expectedError string) require.ErrorAssertionFunc { + return func(t require.TestingT, actualError error, args ...interface{}) { + if stdt, ok := t.(*testing.T); ok { + stdt.Helper() + } + errsToCheck := []error{actualError} + for len(errsToCheck) > 0 { + var err error + err, errsToCheck = errsToCheck[0], errsToCheck[1:] + if err == nil { + continue + } + if verr, ok := err.(*validationError); ok { + if verr.message == expectedError { + return + } + errsToCheck = append(errsToCheck, verr.subErrors...) + } else if expectedError == err.Error() { + return + } + } + t.Errorf("expected error to be or contain suberror %q, got %v", expectedError, actualError) + t.FailNow() + } +} + func TestValidators(t *testing.T) { type spec struct { name string @@ -144,14 +170,14 @@ func TestValidators(t *testing.T) { v: Model{ "foo": pkg, }, - assertion: require.Error, + assertion: hasError(`package key "foo" does not match package name "anakin"`), }, { name: "Model/Error/InvalidPackage", v: Model{ pkgIncorrectDefaultChannel.Name: pkgIncorrectDefaultChannel, }, - assertion: require.Error, + assertion: hasError(`invalid package "anakin"`), }, { name: "Package/Success/Valid", @@ -161,23 +187,23 @@ func TestValidators(t *testing.T) { { name: "Package/Error/NoName", v: &Package{}, - assertion: require.Error, - }, - { - name: "Package/Error/InvalidIcon", - v: &Package{ - Name: "anakin", - Icon: &Icon{Data: mustBase64Decode(svgData)}, - }, - assertion: require.Error, + assertion: hasError("package name must not be empty"), }, + //{ + // name: "Package/Error/InvalidIcon", + // v: &Package{ + // Name: "anakin", + // Icon: &Icon{Data: mustBase64Decode(svgData)}, + // }, + // assertion: hasError("icon mediatype must be set if icon is defined"), + //}, { name: "Package/Error/NoChannels", v: &Package{ Name: "anakin", Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, }, - assertion: require.Error, + assertion: hasError("package must contain at least one channel"), }, { name: "Package/Error/NoDefaultChannel", @@ -186,7 +212,7 @@ func TestValidators(t *testing.T) { Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, Channels: map[string]*Channel{"light": ch}, }, - assertion: require.Error, + assertion: hasError("default channel must be set"), }, { name: "Package/Error/ChannelKeyNameMismatch", @@ -196,7 +222,7 @@ func TestValidators(t *testing.T) { DefaultChannel: ch, Channels: map[string]*Channel{"dark": ch}, }, - assertion: require.Error, + assertion: hasError(`channel key "dark" does not match channel name "light"`), }, { name: "Package/Error/InvalidChannel", @@ -206,7 +232,7 @@ func TestValidators(t *testing.T) { DefaultChannel: ch, Channels: map[string]*Channel{"light": {Name: "light"}}, }, - assertion: require.Error, + assertion: hasError(`invalid channel "light"`), }, { name: "Package/Error/InvalidChannelPackageLink", @@ -216,12 +242,12 @@ func TestValidators(t *testing.T) { DefaultChannel: ch, Channels: map[string]*Channel{"light": ch}, }, - assertion: require.Error, + assertion: hasError(`channel "light" not correctly linked to parent package`), }, { name: "Package/Error/DefaultChannelNotInChannelMap", v: pkgIncorrectDefaultChannel, - assertion: require.Error, + assertion: hasError(`default channel "not-found" not found in channels list`), }, { name: "Icon/Success/ValidSVG", @@ -258,7 +284,7 @@ func TestValidators(t *testing.T) { // Data: nil, // MediaType: "image/svg+xml", // }, - // assertion: require.Error, + // assertion: hasError(`icon data must be set if icon is defined`), //}, //{ // name: "Icon/Error/NoMediaType", @@ -266,7 +292,7 @@ func TestValidators(t *testing.T) { // Data: mustBase64Decode(svgData), // MediaType: "", // }, - // assertion: require.Error, + // assertion: hasError(`icon mediatype must be set if icon is defined`), //}, //{ // name: "Icon/Error/DataIsNotImage", @@ -274,7 +300,7 @@ func TestValidators(t *testing.T) { // Data: []byte("{}"), // MediaType: "application/json", // }, - // assertion: require.Error, + // assertion: hasError(`icon data is not an image`), //}, //{ // name: "Icon/Error/DataDoesNotMatchMediaType", @@ -282,7 +308,7 @@ func TestValidators(t *testing.T) { // Data: mustBase64Decode(svgData), // MediaType: "image/jpeg", // }, - // assertion: require.Error, + // assertion: hasError(`icon media type "image/jpeg" does not match detected media type "image/svg+xml"`), //}, { name: "Channel/Success/Valid", @@ -292,14 +318,14 @@ func TestValidators(t *testing.T) { { name: "Channel/Error/NoName", v: &Channel{}, - assertion: require.Error, + assertion: hasError(`channel name must not be empty`), }, { name: "Channel/Error/NoPackage", v: &Channel{ Name: "light", }, - assertion: require.Error, + assertion: hasError(`package must be set`), }, { name: "Channel/Error/NoBundles", @@ -307,7 +333,7 @@ func TestValidators(t *testing.T) { Package: pkg, Name: "light", }, - assertion: require.Error, + assertion: hasError(`channel must contain at least one bundle`), }, { name: "Channel/Error/InvalidHead", @@ -319,7 +345,7 @@ func TestValidators(t *testing.T) { "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, }, }, - assertion: require.Error, + assertion: hasError(`multiple channel heads found in graph: anakin.v0.0.0, anakin.v0.0.1`), }, { name: "Channel/Error/BundleKeyNameMismatch", @@ -330,7 +356,7 @@ func TestValidators(t *testing.T) { "foo": {Name: "bar"}, }, }, - assertion: require.Error, + assertion: hasError(`bundle key "foo" does not match bundle name "bar"`), }, { name: "Channel/Error/InvalidBundle", @@ -341,7 +367,7 @@ func TestValidators(t *testing.T) { "anakin.v0.0.0": {Name: "anakin.v0.0.0"}, }, }, - assertion: require.Error, + assertion: hasError(`invalid bundle "anakin.v0.0.0"`), }, { name: "Channel/Error/InvalidBundleChannelLink", @@ -357,7 +383,7 @@ func TestValidators(t *testing.T) { }, }, }, - assertion: require.Error, + assertion: hasError(`bundle "anakin.v0.0.0" not correctly linked to parent channel`), }, { name: "Bundle/Success/Valid", @@ -411,7 +437,7 @@ func TestValidators(t *testing.T) { assertion: require.NoError, }, { - name: "Bundle/Error/NoBundleImage/NoBundleData", + name: "Bundle/Error/NoBundleImage", v: &Bundle{ Package: pkg, Channel: ch, @@ -423,19 +449,19 @@ func TestValidators(t *testing.T) { property.MustBuildChannel("light", "anakin.v0.0.1"), }, }, - assertion: require.Error, + assertion: hasError(`bundle image must be set`), }, { name: "Bundle/Error/NoName", v: &Bundle{}, - assertion: require.Error, + assertion: hasError(`name must be set`), }, { name: "Bundle/Error/NoChannel", v: &Bundle{ Name: "anakin.v0.1.0", }, - assertion: require.Error, + assertion: hasError(`channel must be set`), }, { name: "Bundle/Error/NoPackage", @@ -443,7 +469,7 @@ func TestValidators(t *testing.T) { Channel: ch, Name: "anakin.v0.1.0", }, - assertion: require.Error, + assertion: hasError(`package must be set`), }, { name: "Bundle/Error/WrongPackage", @@ -452,7 +478,7 @@ func TestValidators(t *testing.T) { Channel: ch, Name: "anakin.v0.1.0", }, - assertion: require.Error, + assertion: hasError(`package does not match channel's package`), }, { name: "Bundle/Error/InvalidProperty", @@ -461,9 +487,9 @@ func TestValidators(t *testing.T) { Channel: ch, Name: "anakin.v0.1.0", Replaces: "anakin.v0.0.1", - Properties: []property.Property{{Value: json.RawMessage("")}}, + Properties: []property.Property{{Type: "broken", Value: json.RawMessage("")}}, }, - assertion: require.Error, + assertion: hasError(`parse property[0] of type "broken": unexpected end of JSON input`), }, { name: "Bundle/Error/EmptySkipsValue", @@ -475,19 +501,7 @@ func TestValidators(t *testing.T) { Properties: []property.Property{{Type: "custom", Value: json.RawMessage("{}")}}, Skips: []string{""}, }, - assertion: require.Error, - }, - { - name: "Bundle/Error/SkipsNotInPackage", - v: &Bundle{ - Package: pkg, - Channel: ch, - Name: "anakin.v0.1.0", - Replaces: "anakin.v0.0.1", - Properties: []property.Property{{Type: "custom", Value: json.RawMessage("{}")}}, - Skips: []string{"foobar"}, - }, - assertion: require.Error, + assertion: hasError(`skip[0] is empty`), }, { name: "Bundle/Error/MissingPackage", @@ -504,7 +518,7 @@ func TestValidators(t *testing.T) { property.MustBuildChannel("dark", "anakin.v0.0.1"), }, }, - assertion: require.Error, + assertion: hasError(`must be exactly one property with type "olm.package"`), }, { name: "Bundle/Error/MultiplePackages", @@ -523,7 +537,7 @@ func TestValidators(t *testing.T) { property.MustBuildChannel("dark", "anakin.v0.0.1"), }, }, - assertion: require.Error, + assertion: hasError(`must be exactly one property with type "olm.package"`), }, { name: "RelatedImage/Success/Valid", @@ -533,21 +547,13 @@ func TestValidators(t *testing.T) { }, assertion: require.NoError, }, - { - name: "RelatedImage/Error/NoName", - v: RelatedImage{ - Name: "", - Image: "", - }, - assertion: require.Error, - }, { name: "RelatedImage/Error/NoImage", v: RelatedImage{ Name: "foo", Image: "", }, - assertion: require.Error, + assertion: hasError(`image must be set`), }, } for _, s := range specs { diff --git a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go b/vendor/github.com/operator-framework/operator-registry/internal/model/model.go index e0abf6fbf5..330ea84db1 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go +++ b/vendor/github.com/operator-framework/operator-registry/internal/model/model.go @@ -269,9 +269,6 @@ type RelatedImage struct { func (i RelatedImage) Validate() error { result := newValidationError("invalid related image") - if i.Name == "" { - result.subErrors = append(result.subErrors, fmt.Errorf("name must be set")) - } if i.Image == "" { result.subErrors = append(result.subErrors, fmt.Errorf("image must be set")) } From 246e0ce8100697692c78a6f55152616995060940 Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Mon, 12 Jul 2021 17:40:01 -0400 Subject: [PATCH 02/30] Remove pin of etcd and grpc (resolved in etcd v3.5.0). Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: e731c70a5cd62ab1cab7658f1d17f810f525cd8e --- staging/operator-lifecycle-manager/go.mod | 5 --- staging/operator-lifecycle-manager/go.sum | 46 +++++++++++++++++++++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/staging/operator-lifecycle-manager/go.mod b/staging/operator-lifecycle-manager/go.mod index e760883893..3bccaa8fd8 100644 --- a/staging/operator-lifecycle-manager/go.mod +++ b/staging/operator-lifecycle-manager/go.mod @@ -61,11 +61,6 @@ replace ( github.com/openshift/api => github.com/openshift/api v0.0.0-20200331152225-585af27e34fd // release-4.5 github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 // release-4.5 - // pinned because latest etcd does not yet work with the latest grpc version (1.30.0) - go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20200520232829-54ba9589114f - google.golang.org/grpc => google.golang.org/grpc v1.27.0 - google.golang.org/grpc/examples => google.golang.org/grpc/examples v0.0.0-20200709232328-d8193ee9cc3e - // pinned because no tag supports 1.18 yet sigs.k8s.io/structured-merge-diff => sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 ) diff --git a/staging/operator-lifecycle-manager/go.sum b/staging/operator-lifecycle-manager/go.sum index 685a6f6b2c..0f485b6228 100644 --- a/staging/operator-lifecycle-manager/go.sum +++ b/staging/operator-lifecycle-manager/go.sum @@ -1,4 +1,5 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -169,6 +170,9 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -290,7 +294,12 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= @@ -440,6 +449,7 @@ github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -449,7 +459,6 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k= github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -677,6 +686,7 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1056,8 +1066,9 @@ go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200520232829-54ba9589114f h1:pBCD+Z7cy5WPTq+R6MmJJvDRpn88cp7bmTypBsn91g4= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200520232829-54ba9589114f/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= @@ -1160,6 +1171,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -1184,6 +1196,7 @@ golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/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-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-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1249,6 +1262,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cO golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20180823144017-11551d06cbcc/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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1346,9 +1360,11 @@ golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1423,6 +1439,7 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1462,8 +1479,28 @@ google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200709232328-d8193ee9cc3e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1532,6 +1569,7 @@ gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= helm.sh/helm/v3 v3.6.1 h1:TQ6q4pAatXr7qh2fbLcb0oNd0I3J7kv26oo5cExKTtc= helm.sh/helm/v3 v3.6.1/go.mod h1:mIIus8EOqj+obtycw3sidsR4ORr2aFDmXMSI3k+oeVY= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 1e5aef2962397bb11e669d2f42cdf26f5f454ff6 Mon Sep 17 00:00:00 2001 From: Ankita Thomas Date: Mon, 12 Jul 2021 10:52:16 -0400 Subject: [PATCH 03/30] move DC opm commands out of alpha Signed-off-by: Ankita Thomas Upstream-repository: operator-registry Upstream-commit: 9e88b877c8324d5fd027e512ad845b344cc4168a --- staging/operator-registry/cmd/opm/alpha/cmd.go | 6 +----- staging/operator-registry/cmd/opm/{alpha => }/init/cmd.go | 0 .../operator-registry/cmd/opm/{alpha => }/render/cmd.go | 0 staging/operator-registry/cmd/opm/root/cmd.go | 6 +++++- .../operator-registry/cmd/opm/{alpha => }/serve/serve.go | 0 .../cmd/opm/{alpha => }/validate/validate.go | 0 .../operator-registry/cmd/opm/alpha/cmd.go | 6 +----- .../operator-registry/cmd/opm/{alpha => }/init/cmd.go | 0 .../operator-registry/cmd/opm/{alpha => }/render/cmd.go | 0 .../operator-registry/cmd/opm/root/cmd.go | 6 +++++- .../operator-registry/cmd/opm/{alpha => }/serve/serve.go | 0 .../cmd/opm/{alpha => }/validate/validate.go | 0 vendor/modules.txt | 8 ++++---- 13 files changed, 16 insertions(+), 16 deletions(-) rename staging/operator-registry/cmd/opm/{alpha => }/init/cmd.go (100%) rename staging/operator-registry/cmd/opm/{alpha => }/render/cmd.go (100%) rename staging/operator-registry/cmd/opm/{alpha => }/serve/serve.go (100%) rename staging/operator-registry/cmd/opm/{alpha => }/validate/validate.go (100%) rename vendor/github.com/operator-framework/operator-registry/cmd/opm/{alpha => }/init/cmd.go (100%) rename vendor/github.com/operator-framework/operator-registry/cmd/opm/{alpha => }/render/cmd.go (100%) rename vendor/github.com/operator-framework/operator-registry/cmd/opm/{alpha => }/serve/serve.go (100%) rename vendor/github.com/operator-framework/operator-registry/cmd/opm/{alpha => }/validate/validate.go (100%) diff --git a/staging/operator-registry/cmd/opm/alpha/cmd.go b/staging/operator-registry/cmd/opm/alpha/cmd.go index 9c06ae2cfd..323a19f817 100644 --- a/staging/operator-registry/cmd/opm/alpha/cmd.go +++ b/staging/operator-registry/cmd/opm/alpha/cmd.go @@ -4,10 +4,6 @@ import ( "github.com/spf13/cobra" "github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle" - initcmd "github.com/operator-framework/operator-registry/cmd/opm/alpha/init" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/render" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/serve" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/validate" ) func NewCmd() *cobra.Command { @@ -17,6 +13,6 @@ func NewCmd() *cobra.Command { Short: "Run an alpha subcommand", } - runCmd.AddCommand(bundle.NewCmd(), initcmd.NewCmd(), serve.NewCmd(), render.NewCmd(), validate.NewCmd()) + runCmd.AddCommand(bundle.NewCmd()) return runCmd } diff --git a/staging/operator-registry/cmd/opm/alpha/init/cmd.go b/staging/operator-registry/cmd/opm/init/cmd.go similarity index 100% rename from staging/operator-registry/cmd/opm/alpha/init/cmd.go rename to staging/operator-registry/cmd/opm/init/cmd.go diff --git a/staging/operator-registry/cmd/opm/alpha/render/cmd.go b/staging/operator-registry/cmd/opm/render/cmd.go similarity index 100% rename from staging/operator-registry/cmd/opm/alpha/render/cmd.go rename to staging/operator-registry/cmd/opm/render/cmd.go diff --git a/staging/operator-registry/cmd/opm/root/cmd.go b/staging/operator-registry/cmd/opm/root/cmd.go index 272981bfd5..7b07ccbc75 100644 --- a/staging/operator-registry/cmd/opm/root/cmd.go +++ b/staging/operator-registry/cmd/opm/root/cmd.go @@ -6,7 +6,11 @@ import ( "github.com/operator-framework/operator-registry/cmd/opm/alpha" "github.com/operator-framework/operator-registry/cmd/opm/index" + initcmd "github.com/operator-framework/operator-registry/cmd/opm/init" "github.com/operator-framework/operator-registry/cmd/opm/registry" + "github.com/operator-framework/operator-registry/cmd/opm/render" + "github.com/operator-framework/operator-registry/cmd/opm/serve" + "github.com/operator-framework/operator-registry/cmd/opm/validate" "github.com/operator-framework/operator-registry/cmd/opm/version" ) @@ -23,7 +27,7 @@ func NewCmd() *cobra.Command { }, } - cmd.AddCommand(registry.NewOpmRegistryCmd(), alpha.NewCmd()) + cmd.AddCommand(registry.NewOpmRegistryCmd(), alpha.NewCmd(), initcmd.NewCmd(), serve.NewCmd(), render.NewCmd(), validate.NewCmd()) index.AddCommand(cmd) version.AddCommand(cmd) diff --git a/staging/operator-registry/cmd/opm/alpha/serve/serve.go b/staging/operator-registry/cmd/opm/serve/serve.go similarity index 100% rename from staging/operator-registry/cmd/opm/alpha/serve/serve.go rename to staging/operator-registry/cmd/opm/serve/serve.go diff --git a/staging/operator-registry/cmd/opm/alpha/validate/validate.go b/staging/operator-registry/cmd/opm/validate/validate.go similarity index 100% rename from staging/operator-registry/cmd/opm/alpha/validate/validate.go rename to staging/operator-registry/cmd/opm/validate/validate.go diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go index 9c06ae2cfd..323a19f817 100644 --- a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go +++ b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go @@ -4,10 +4,6 @@ import ( "github.com/spf13/cobra" "github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle" - initcmd "github.com/operator-framework/operator-registry/cmd/opm/alpha/init" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/render" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/serve" - "github.com/operator-framework/operator-registry/cmd/opm/alpha/validate" ) func NewCmd() *cobra.Command { @@ -17,6 +13,6 @@ func NewCmd() *cobra.Command { Short: "Run an alpha subcommand", } - runCmd.AddCommand(bundle.NewCmd(), initcmd.NewCmd(), serve.NewCmd(), render.NewCmd(), validate.NewCmd()) + runCmd.AddCommand(bundle.NewCmd()) return runCmd } diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/init/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/init/cmd.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/init/cmd.go rename to vendor/github.com/operator-framework/operator-registry/cmd/opm/init/cmd.go diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/render/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/render/cmd.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/render/cmd.go rename to vendor/github.com/operator-framework/operator-registry/cmd/opm/render/cmd.go diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/root/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/root/cmd.go index 272981bfd5..7b07ccbc75 100644 --- a/vendor/github.com/operator-framework/operator-registry/cmd/opm/root/cmd.go +++ b/vendor/github.com/operator-framework/operator-registry/cmd/opm/root/cmd.go @@ -6,7 +6,11 @@ import ( "github.com/operator-framework/operator-registry/cmd/opm/alpha" "github.com/operator-framework/operator-registry/cmd/opm/index" + initcmd "github.com/operator-framework/operator-registry/cmd/opm/init" "github.com/operator-framework/operator-registry/cmd/opm/registry" + "github.com/operator-framework/operator-registry/cmd/opm/render" + "github.com/operator-framework/operator-registry/cmd/opm/serve" + "github.com/operator-framework/operator-registry/cmd/opm/validate" "github.com/operator-framework/operator-registry/cmd/opm/version" ) @@ -23,7 +27,7 @@ func NewCmd() *cobra.Command { }, } - cmd.AddCommand(registry.NewOpmRegistryCmd(), alpha.NewCmd()) + cmd.AddCommand(registry.NewOpmRegistryCmd(), alpha.NewCmd(), initcmd.NewCmd(), serve.NewCmd(), render.NewCmd(), validate.NewCmd()) index.AddCommand(cmd) version.AddCommand(cmd) diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/serve/serve.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/serve/serve.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/serve/serve.go rename to vendor/github.com/operator-framework/operator-registry/cmd/opm/serve/serve.go diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/validate/validate.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/validate/validate.go similarity index 100% rename from vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/validate/validate.go rename to vendor/github.com/operator-framework/operator-registry/cmd/opm/validate/validate.go diff --git a/vendor/modules.txt b/vendor/modules.txt index 5b27540840..37f06ed339 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -579,13 +579,13 @@ github.com/operator-framework/operator-registry/cmd/initializer github.com/operator-framework/operator-registry/cmd/opm github.com/operator-framework/operator-registry/cmd/opm/alpha github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle -github.com/operator-framework/operator-registry/cmd/opm/alpha/init -github.com/operator-framework/operator-registry/cmd/opm/alpha/render -github.com/operator-framework/operator-registry/cmd/opm/alpha/serve -github.com/operator-framework/operator-registry/cmd/opm/alpha/validate github.com/operator-framework/operator-registry/cmd/opm/index +github.com/operator-framework/operator-registry/cmd/opm/init github.com/operator-framework/operator-registry/cmd/opm/registry +github.com/operator-framework/operator-registry/cmd/opm/render github.com/operator-framework/operator-registry/cmd/opm/root +github.com/operator-framework/operator-registry/cmd/opm/serve +github.com/operator-framework/operator-registry/cmd/opm/validate github.com/operator-framework/operator-registry/cmd/opm/version github.com/operator-framework/operator-registry/cmd/registry-server github.com/operator-framework/operator-registry/internal/action From 1529be4743f8ededbfb3f233c946f5b8134fdfe5 Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Tue, 13 Jul 2021 15:42:39 -0400 Subject: [PATCH 04/30] Translate legacy "bundle dependencies" to properties. Operator dependencies are expressed as properties, but there was initially a notion of dependencies as distinct from properties. For that reason, catalog-operator must support existing catalog images that serve separate Bundle.dependencies and Bundle.properties fields by translating the three legacy dependency types (olm.label, olm.package, and olm.gvk) into their corresponding properties. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: c918a85eb7ef0c1ea58ebf27fabd8d2393afe9b3 --- .../registry/resolver/installabletypes.go | 20 +- .../controller/registry/resolver/operators.go | 173 ++++++++++++------ .../registry/resolver/operators_test.go | 101 +++++----- .../controller/registry/resolver/resolver.go | 63 +++---- .../registry/resolver/resolver_test.go | 58 +++++- .../registry/resolver/installabletypes.go | 20 +- .../controller/registry/resolver/operators.go | 173 ++++++++++++------ .../controller/registry/resolver/resolver.go | 63 +++---- 8 files changed, 436 insertions(+), 235 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go index 1fd00375f3..0c017c7cc5 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go @@ -60,24 +60,30 @@ func NewBundleInstallableFromOperator(o *Operator) (BundleInstallable, error) { if src == nil { return BundleInstallable{}, fmt.Errorf("unable to resolve the source of bundle %s", o.Identifier()) } + id := bundleId(o.Identifier(), o.Channel(), src.Catalog) var constraints []solver.Constraint + if src.Catalog.Virtual() && src.Subscription == nil { + // CSVs already associated with a Subscription + // may be replaced, but freestanding CSVs must + // appear in any solution. + constraints = append(constraints, PrettyConstraint( + solver.Mandatory(), + fmt.Sprintf("clusterserviceversion %s exists and is not referenced by a subscription", o.Identifier()), + )) + } for _, p := range o.bundle.GetProperties() { if p.GetType() == operatorregistry.DeprecatedType { constraints = append(constraints, PrettyConstraint( solver.Prohibited(), - fmt.Sprintf("bundle %s is deprecated", bundleId(o.Identifier(), o.Channel(), src.Catalog)), + fmt.Sprintf("bundle %s is deprecated", id), )) break } } - return NewBundleInstallable(o.Identifier(), o.Channel(), src.Catalog, constraints...), nil -} - -func NewBundleInstallable(bundle, channel string, catalog registry.CatalogKey, constraints ...solver.Constraint) BundleInstallable { return BundleInstallable{ - identifier: bundleId(bundle, channel, catalog), + identifier: id, constraints: constraints, - } + }, nil } type GenericInstallable struct { diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go index 19a0b933ed..1c21425bf2 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go @@ -11,10 +11,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-registry/pkg/api" opregistry "github.com/operator-framework/operator-registry/pkg/registry" - - "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" ) type APISet map[opregistry.APIKey]struct{} @@ -197,6 +196,7 @@ type OperatorSourceInfo struct { StartingCSV string Catalog registry.CatalogKey DefaultChannel bool + Subscription *v1alpha1.Subscription } func (i *OperatorSourceInfo) String() string { @@ -216,7 +216,6 @@ type OperatorSurface interface { SourceInfo() *OperatorSourceInfo Bundle() *api.Bundle Inline() bool - Dependencies() []*api.Dependency Properties() []*api.Property Skips() []string } @@ -229,7 +228,6 @@ type Operator struct { version *semver.Version bundle *api.Bundle sourceInfo *OperatorSourceInfo - dependencies []*api.Dependency properties []*api.Property skips []string } @@ -261,21 +259,27 @@ func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey reg // legacy support - if the api doesn't contain properties/dependencies, build them from required/provided apis properties := bundle.Properties if len(properties) == 0 { - properties, err = apisToProperties(provided) + properties, err = providedAPIsToProperties(provided) if err != nil { return nil, err } } - dependencies := bundle.Dependencies - if len(dependencies) == 0 { - dependencies, err = apisToDependencies(required) + if len(bundle.Dependencies) > 0 { + ps, err := legacyDependenciesToProperties(bundle.Dependencies) + if err != nil { + return nil, fmt.Errorf("failed to translate legacy dependencies to properties: %w", err) + } + properties = append(properties, ps...) + } else { + ps, err := requiredAPIsToProperties(required) if err != nil { return nil, err } + properties = append(properties, ps...) } // legacy support - if the grpc api doesn't contain required/provided apis, fallback to csv parsing - if len(required) == 0 && len(provided) == 0 && len(properties) == 0 && len(dependencies) == 0 { + if len(required) == 0 && len(provided) == 0 && len(properties) == 0 { // fallback to csv parsing if bundle.CsvJson == "" { if bundle.GetBundlePath() != "" { @@ -307,7 +311,6 @@ func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey reg requiredAPIs: required, bundle: bundle, sourceInfo: sourceInfo, - dependencies: dependencies, properties: properties, skips: bundle.Skips, }, nil @@ -338,15 +341,15 @@ func NewOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*Operator, requiredAPIs[opregistry.APIKey{Group: api.Group, Version: api.Version, Kind: api.Kind, Plural: api.Name}] = struct{}{} } - dependencies, err := apisToDependencies(requiredAPIs) + properties, err := providedAPIsToProperties(providedAPIs) if err != nil { return nil, err } - - properties, err := apisToProperties(providedAPIs) + dependencies, err := requiredAPIsToProperties(requiredAPIs) if err != nil { return nil, err } + properties = append(properties, dependencies...) return &Operator{ name: csv.GetName(), @@ -354,7 +357,6 @@ func NewOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*Operator, providedAPIs: providedAPIs, requiredAPIs: requiredAPIs, sourceInfo: &ExistingOperator, - dependencies: dependencies, properties: properties, }, nil } @@ -413,48 +415,48 @@ func (o *Operator) Inline() bool { return o.bundle != nil && o.bundle.GetBundlePath() == "" } -func (o *Operator) Dependencies() []*api.Dependency { - return o.dependencies -} - func (o *Operator) Properties() []*api.Property { return o.properties } func (o *Operator) DependencyPredicates() (predicates []OperatorPredicate, err error) { predicates = make([]OperatorPredicate, 0) - for _, d := range o.Dependencies() { - var p OperatorPredicate - if d == nil || d.Type == "" { - continue - } - p, err = PredicateForDependency(d) + for _, property := range o.Properties() { + predicate, err := PredicateForProperty(property) if err != nil { - return + return nil, err + } + if predicate == nil { + continue } - predicates = append(predicates, p) + predicates = append(predicates, predicate) } return } -// TODO: this should go in its own dependency/predicate builder package -// TODO: can we make this more extensible, i.e. via cue -func PredicateForDependency(dependency *api.Dependency) (OperatorPredicate, error) { - p, ok := predicates[dependency.Type] +func PredicateForProperty(property *api.Property) (OperatorPredicate, error) { + if property == nil { + return nil, nil + } + p, ok := predicates[property.Type] if !ok { - return nil, fmt.Errorf("no predicate for dependency type %s", dependency.Type) + return nil, nil } - return p(dependency.Value) + return p(property.Value) } var predicates = map[string]func(string) (OperatorPredicate, error){ - opregistry.GVKType: predicateForGVKDependency, - opregistry.PackageType: predicateForPackageDependency, - opregistry.LabelType: predicateForLabelDependency, + "olm.gvk.required": predicateForRequiredGVKProperty, + "olm.package.required": predicateForRequiredPackageProperty, + "olm.label.required": predicateForRequiredLabelProperty, } -func predicateForGVKDependency(value string) (OperatorPredicate, error) { - var gvk opregistry.GVKDependency +func predicateForRequiredGVKProperty(value string) (OperatorPredicate, error) { + var gvk struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + } if err := json.Unmarshal([]byte(value), &gvk); err != nil { return nil, err } @@ -465,44 +467,51 @@ func predicateForGVKDependency(value string) (OperatorPredicate, error) { }), nil } -func predicateForPackageDependency(value string) (OperatorPredicate, error) { - var pkg opregistry.PackageDependency +func predicateForRequiredPackageProperty(value string) (OperatorPredicate, error) { + var pkg struct { + PackageName string `json:"packageName"` + VersionRange string `json:"versionRange"` + } if err := json.Unmarshal([]byte(value), &pkg); err != nil { return nil, err } - ver, err := semver.ParseRange(pkg.Version) + ver, err := semver.ParseRange(pkg.VersionRange) if err != nil { return nil, err } - return And(WithPackage(pkg.PackageName), WithVersionInRange(ver)), nil } -func predicateForLabelDependency(value string) (OperatorPredicate, error) { - var label opregistry.LabelDependency +func predicateForRequiredLabelProperty(value string) (OperatorPredicate, error) { + var label struct { + Label string `json:"label"` + } if err := json.Unmarshal([]byte(value), &label); err != nil { return nil, err } - return WithLabel(label.Label), nil } -func apisToDependencies(apis APISet) (out []*api.Dependency, err error) { +func requiredAPIsToProperties(apis APISet) (out []*api.Property, err error) { if len(apis) == 0 { return } - out = make([]*api.Dependency, 0) + out = make([]*api.Property, 0) for a := range apis { - val, err := json.Marshal(opregistry.GVKDependency{ + val, err := json.Marshal(struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + }{ Group: a.Group, - Kind: a.Kind, Version: a.Version, + Kind: a.Kind, }) if err != nil { return nil, err } - out = append(out, &api.Dependency{ - Type: opregistry.GVKType, + out = append(out, &api.Property{ + Type: "olm.gvk.required", Value: string(val), }) } @@ -512,13 +521,13 @@ func apisToDependencies(apis APISet) (out []*api.Dependency, err error) { return nil, nil } -func apisToProperties(apis APISet) (out []*api.Property, err error) { +func providedAPIsToProperties(apis APISet) (out []*api.Property, err error) { out = make([]*api.Property, 0) for a := range apis { val, err := json.Marshal(opregistry.GVKProperty{ Group: a.Group, - Kind: a.Kind, Version: a.Version, + Kind: a.Kind, }) if err != nil { panic(err) @@ -533,3 +542,63 @@ func apisToProperties(apis APISet) (out []*api.Property, err error) { } return nil, nil } + +func legacyDependenciesToProperties(dependencies []*api.Dependency) ([]*api.Property, error) { + var result []*api.Property + for _, dependency := range dependencies { + switch dependency.Type { + case "olm.gvk": + type gvk struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + } + var vfrom gvk + if err := json.Unmarshal([]byte(dependency.Value), &vfrom); err != nil { + return nil, fmt.Errorf("failed to unmarshal legacy 'olm.gvk' dependency: %w", err) + } + vto := gvk{ + Group: vfrom.Group, + Version: vfrom.Version, + Kind: vfrom.Kind, + } + vb, err := json.Marshal(&vto) + if err != nil { + return nil, fmt.Errorf("unexpected error marshaling generated 'olm.package.required' property: %w", err) + } + result = append(result, &api.Property{ + Type: "olm.gvk.required", + Value: string(vb), + }) + case "olm.package": + var vfrom struct { + PackageName string `json:"packageName"` + VersionRange string `json:"version"` + } + if err := json.Unmarshal([]byte(dependency.Value), &vfrom); err != nil { + return nil, fmt.Errorf("failed to unmarshal legacy 'olm.package' dependency: %w", err) + } + vto := struct { + PackageName string `json:"packageName"` + VersionRange string `json:"versionRange"` + }{ + PackageName: vfrom.PackageName, + VersionRange: vfrom.VersionRange, + } + vb, err := json.Marshal(&vto) + if err != nil { + return nil, fmt.Errorf("unexpected error marshaling generated 'olm.package.required' property: %w", err) + } + result = append(result, &api.Property{ + Type: "olm.package.required", + Value: string(vb), + }) + case "olm.label": + result = append(result, &api.Property{ + Type: "olm.label.required", + Value: dependency.Value, + }) + } + } + return result, nil +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators_test.go index 5cbbdeabcd..4f3897fb94 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/operators_test.go @@ -737,7 +737,7 @@ func TestAPIMultiOwnerSet_PopAPIKey(t *testing.T) { { name: "OneApi/OneOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, }, }, @@ -745,7 +745,7 @@ func TestAPIMultiOwnerSet_PopAPIKey(t *testing.T) { { name: "OneApi/MultiOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, @@ -754,11 +754,11 @@ func TestAPIMultiOwnerSet_PopAPIKey(t *testing.T) { { name: "MultipleApi/MultiOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, - opregistry.APIKey{"g2", "v2", "k2", "p2"}: map[string]OperatorSurface{ + {Group: "g2", Version: "v2", Kind: "k2", Plural: "p2"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, @@ -797,7 +797,7 @@ func TestAPIMultiOwnerSet_PopAPIRequirers(t *testing.T) { { name: "OneApi/OneOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, }, }, @@ -808,7 +808,7 @@ func TestAPIMultiOwnerSet_PopAPIRequirers(t *testing.T) { { name: "OneApi/MultiOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, @@ -821,11 +821,11 @@ func TestAPIMultiOwnerSet_PopAPIRequirers(t *testing.T) { { name: "MultipleApi/MultiOwner", s: map[opregistry.APIKey]OperatorSet{ - opregistry.APIKey{"g", "v", "k", "p"}: map[string]OperatorSurface{ + {Group: "g", Version: "v", Kind: "k", Plural: "p"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, - opregistry.APIKey{"g2", "v2", "k2", "p2"}: map[string]OperatorSurface{ + {Group: "g2", Version: "v2", Kind: "k2", Plural: "p2"}: map[string]OperatorSurface{ "owner1": &Operator{name: "op1"}, "owner2": &Operator{name: "op2"}, }, @@ -879,7 +879,7 @@ func TestOperatorSourceInfo_String(t *testing.T) { i := &OperatorSourceInfo{ Package: tt.fields.Package, Channel: tt.fields.Channel, - Catalog: registry.CatalogKey{tt.fields.CatalogSource, tt.fields.CatalogSourceNamespace}, + Catalog: registry.CatalogKey{Name: tt.fields.CatalogSource, Namespace: tt.fields.CatalogSourceNamespace}, } if got := i.String(); got != tt.want { t.Errorf("OperatorSourceInfo.String() = %v, want %v", got, tt.want) @@ -889,7 +889,7 @@ func TestOperatorSourceInfo_String(t *testing.T) { } func TestNewOperatorFromBundle(t *testing.T) { - version := opver.OperatorVersion{semver.MustParse("0.1.0-abc")} + version := opver.OperatorVersion{Version: semver.MustParse("0.1.0-abc")} csv := v1alpha1.ClusterServiceVersion{ TypeMeta: metav1.TypeMeta{ Kind: v1alpha1.ClusterServiceVersionKind, @@ -1087,7 +1087,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1137,14 +1137,12 @@ func TestNewOperatorFromBundle(t *testing.T) { Type: "olm.gvk", Value: "{\"group\":\"apis.group.com\",\"kind\":\"OwnedAPI\",\"version\":\"v1\"}", }, - }, - dependencies: []*api.Dependency{ { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"crd.group.com\",\"kind\":\"RequiredCRD\",\"version\":\"v1\"}", }, { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"apis.group.com\",\"kind\":\"RequiredAPI\",\"version\":\"v1\"}", }, }, @@ -1152,7 +1150,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1172,7 +1170,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1221,14 +1219,12 @@ func TestNewOperatorFromBundle(t *testing.T) { Type: "olm.gvk", Value: "{\"group\":\"apis.group.com\",\"kind\":\"OwnedAPI\",\"version\":\"v1\"}", }, - }, - dependencies: []*api.Dependency{ { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"apis.group.com\",\"kind\":\"RequiredAPI\",\"version\":\"v1\"}", }, { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"crd.group.com\",\"kind\":\"RequiredCRD\",\"version\":\"v1\"}", }, }, @@ -1237,7 +1233,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1257,7 +1253,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, DefaultChannel: true, }, }, @@ -1278,7 +1274,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1302,14 +1298,12 @@ func TestNewOperatorFromBundle(t *testing.T) { Type: "olm.gvk", Value: "{\"group\":\"apis.group.com\",\"kind\":\"OwnedAPI\",\"version\":\"v1\"}", }, - }, - dependencies: []*api.Dependency{ { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"crd.group.com\",\"kind\":\"RequiredCRD\",\"version\":\"v1\"}", }, { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"apis.group.com\",\"kind\":\"RequiredAPI\",\"version\":\"v1\"}", }, }, @@ -1317,7 +1311,7 @@ func TestNewOperatorFromBundle(t *testing.T) { sourceInfo: &OperatorSourceInfo{ Package: "testPackage", Channel: "testChannel", - Catalog: registry.CatalogKey{"source", "testNamespace"}, + Catalog: registry.CatalogKey{Name: "source", Namespace: "testNamespace"}, }, }, }, @@ -1326,16 +1320,15 @@ func TestNewOperatorFromBundle(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := NewOperatorFromBundle(tt.args.bundle, "", tt.args.sourceKey, tt.args.defaultChannel) require.Equal(t, tt.wantErr, err) - require.ElementsMatch(t, tt.want.dependencies, got.dependencies) - require.ElementsMatch(t, tt.want.properties, got.properties) - tt.want.properties, tt.want.dependencies, got.dependencies, got.properties = nil, nil, nil, nil + requirePropertiesEqual(t, tt.want.properties, got.properties) + tt.want.properties, got.properties = nil, nil require.Equal(t, tt.want, got) }) } } func TestNewOperatorFromCSV(t *testing.T) { - version := opver.OperatorVersion{semver.MustParse("0.1.0-abc")} + version := opver.OperatorVersion{Version: semver.MustParse("0.1.0-abc")} type args struct { csv *v1alpha1.ClusterServiceVersion } @@ -1455,13 +1448,13 @@ func TestNewOperatorFromCSV(t *testing.T) { {Group: "g", Version: "v1", Kind: "APIKind", Plural: "apikinds"}: {}, {Group: "g", Version: "v1", Kind: "CRDKind", Plural: "crdkinds"}: {}, }, - dependencies: []*api.Dependency{ + properties: []*api.Property{ { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"g\",\"kind\":\"APIKind\",\"version\":\"v1\"}", }, { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"g\",\"kind\":\"CRDKind\",\"version\":\"v1\"}", }, }, @@ -1534,14 +1527,12 @@ func TestNewOperatorFromCSV(t *testing.T) { Type: "olm.gvk", Value: "{\"group\":\"g\",\"kind\":\"CRDOwnedKind\",\"version\":\"v1\"}", }, - }, - dependencies: []*api.Dependency{ { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"g2\",\"kind\":\"APIReqKind\",\"version\":\"v1\"}", }, { - Type: "olm.gvk", + Type: "olm.gvk.required", Value: "{\"group\":\"g2\",\"kind\":\"CRDReqKind\",\"version\":\"v1\"}", }, }, @@ -1554,10 +1545,34 @@ func TestNewOperatorFromCSV(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := NewOperatorFromV1Alpha1CSV(tt.args.csv) require.Equal(t, tt.wantErr, err) - require.ElementsMatch(t, tt.want.dependencies, got.dependencies) - require.ElementsMatch(t, tt.want.properties, got.properties) - tt.want.properties, tt.want.dependencies, got.dependencies, got.properties = nil, nil, nil, nil + requirePropertiesEqual(t, tt.want.properties, got.properties) + tt.want.properties, got.properties = nil, nil require.Equal(t, tt.want, got) }) } } + +func requirePropertiesEqual(t *testing.T, a, b []*api.Property) { + type Property struct { + Type string + Value interface{} + } + nice := func(in *api.Property) Property { + var i interface{} + if err := json.Unmarshal([]byte(in.Value), &i); err != nil { + t.Fatalf("property value %q could not be unmarshaled as json: %s", in.Value, err) + } + return Property{ + Type: in.Type, + Value: i, + } + } + var l, r []Property + for _, p := range a { + l = append(l, nice(p)) + } + for _, p := range b { + r = append(r, nice(p)) + } + require.ElementsMatch(t, l, r) +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index e2ee4a66e0..a4473f36bf 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -55,12 +55,16 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust startingCSVs := make(map[string]struct{}) // build a virtual catalog of all currently installed CSVs - existingSnapshot, existingInstallables, err := r.newSnapshotForNamespace(namespaces[0], subs, csvs) + existingSnapshot, err := r.newSnapshotForNamespace(namespaces[0], subs, csvs) if err != nil { return nil, err } namespacedCache := r.cache.Namespaced(namespaces...).WithExistingOperators(existingSnapshot) + _, existingInstallables, err := r.getBundleInstallables(registry.NewVirtualCatalogKey(namespaces[0]), existingSnapshot.Find(), namespacedCache, visited) + if err != nil { + return nil, err + } for _, i := range existingInstallables { installables[i.Identifier()] = i } @@ -248,7 +252,8 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu candidates := make([]*BundleInstallable, 0) for _, o := range Filter(sortedBundles, channelPredicates...) { predicates := append(cachePredicates, WithCSVName(o.Identifier())) - id, installable, err := r.getBundleInstallables(catalog, predicates, namespacedCache, visited) + stack := namespacedCache.Catalog(catalog).Find(predicates...) + id, installable, err := r.getBundleInstallables(catalog, stack, namespacedCache, visited) if err != nil { return nil, err } @@ -292,17 +297,10 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu return installables, nil } -func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, predicates []OperatorPredicate, namespacedCache MultiCatalogOperatorFinder, visited map[OperatorSurface]*BundleInstallable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleInstallable, error) { +func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, bundleStack []*Operator, namespacedCache MultiCatalogOperatorFinder, visited map[OperatorSurface]*BundleInstallable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleInstallable, error) { errs := make([]error, 0) installables := make(map[solver.Identifier]*BundleInstallable, 0) // all installables, including dependencies - var finder OperatorFinder = namespacedCache - if !catalog.Empty() { - finder = namespacedCache.Catalog(catalog) - } - - bundleStack := finder.Find(predicates...) - // track the first layer of installable ids var initial = make(map[*Operator]struct{}) for _, o := range bundleStack { @@ -353,11 +351,18 @@ func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, predica } sources[*si] = struct{}{} - sourcePredicate = Or(sourcePredicate, And( - WithPackage(si.Package), - WithChannel(si.Channel), - WithCatalog(si.Catalog), - )) + if si.Catalog.Virtual() { + sourcePredicate = Or(sourcePredicate, And( + WithCSVName(b.Identifier()), + WithCatalog(si.Catalog), + )) + } else { + sourcePredicate = Or(sourcePredicate, And( + WithPackage(si.Package), + WithChannel(si.Channel), + WithCatalog(si.Catalog), + )) + } } sortedBundles, err := r.sortBundles(namespacedCache.FindPreferred(&bundle.sourceInfo.Catalog, sourcePredicate)) if err != nil { @@ -441,15 +446,14 @@ func (r *SatResolver) inferProperties(csv *v1alpha1.ClusterServiceVersion, subs return properties, nil } -func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1.Subscription, csvs []*v1alpha1.ClusterServiceVersion) (*CatalogSnapshot, []solver.Installable, error) { - installables := make([]solver.Installable, 0) +func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1.Subscription, csvs []*v1alpha1.ClusterServiceVersion) (*CatalogSnapshot, error) { existingOperatorCatalog := registry.NewVirtualCatalogKey(namespace) // build a catalog snapshot of CSVs without subscriptions - csvsWithSubscriptions := make(map[*v1alpha1.ClusterServiceVersion]struct{}) + csvSubscriptions := make(map[*v1alpha1.ClusterServiceVersion]*v1alpha1.Subscription) for _, sub := range subs { for _, csv := range csvs { if csv.Name == sub.Status.InstalledCSV { - csvsWithSubscriptions[csv] = struct{}{} + csvSubscriptions[csv] = sub break } } @@ -457,17 +461,9 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 var csvsMissingProperties []*v1alpha1.ClusterServiceVersion standaloneOperators := make([]*Operator, 0) for _, csv := range csvs { - var constraints []solver.Constraint - if _, ok := csvsWithSubscriptions[csv]; !ok { - // CSVs already associated with a Subscription - // may be replaced, but freestanding CSVs must - // appear in any solution. - constraints = append(constraints, solver.Mandatory()) - } - op, err := NewOperatorFromV1Alpha1CSV(csv) if err != nil { - return nil, nil, err + return nil, err } if anno, ok := csv.GetAnnotations()[projection.PropertiesAnnotationKey]; !ok { @@ -478,13 +474,14 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 op.properties = append(op.properties, inferred...) } } else if props, err := projection.PropertyListFromPropertiesAnnotation(anno); err != nil { - return nil, nil, fmt.Errorf("failed to retrieve properties of csv %q: %w", csv.GetName(), err) + return nil, fmt.Errorf("failed to retrieve properties of csv %q: %w", csv.GetName(), err) } else { op.properties = props } op.sourceInfo = &OperatorSourceInfo{ - Catalog: existingOperatorCatalog, + Catalog: existingOperatorCatalog, + Subscription: csvSubscriptions[csv], } // Try to determine source package name from properties and add to SourceInfo. for _, p := range op.properties { @@ -501,10 +498,6 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 } standaloneOperators = append(standaloneOperators, op) - - // all standalone operators are mandatory - i := NewBundleInstallable(op.Identifier(), "", existingOperatorCatalog, constraints...) - installables = append(installables, &i) } if len(csvsMissingProperties) > 0 { @@ -515,7 +508,7 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 r.log.Infof("considered csvs without properties annotation during resolution: %v", names) } - return NewRunningOperatorSnapshot(r.log, existingOperatorCatalog, standaloneOperators), installables, nil + return NewRunningOperatorSnapshot(r.log, existingOperatorCatalog, standaloneOperators), nil } func (r *SatResolver) addInvariants(namespacedCache MultiCatalogOperatorFinder, installables map[solver.Identifier]solver.Installable) { diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go index 0472ef65fe..22106e1558 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go @@ -1298,8 +1298,19 @@ func getFakeOperatorCache(fakedNamespacedOperatorCache NamespacedOperatorCache) func genOperator(name, version, replaces, pkg, channel, catalogName, catalogNamespace string, requiredAPIs, providedAPIs APISet, dependencies []*api.Dependency, defaultChannel string, deprecated bool) *Operator { semversion, _ := semver.Make(version) + properties := apiSetToProperties(providedAPIs, nil, deprecated) if len(dependencies) == 0 { - dependencies = apiSetToDependencies(requiredAPIs, nil) + ps, err := requiredAPIsToProperties(requiredAPIs) + if err != nil { + panic(err) + } + properties = append(properties, ps...) + } else { + ps, err := legacyDependenciesToProperties(dependencies) + if err != nil { + panic(err) + } + properties = append(properties, ps...) } o := &Operator{ name: name, @@ -1309,10 +1320,9 @@ func genOperator(name, version, replaces, pkg, channel, catalogName, catalogName PackageName: pkg, ChannelName: channel, Dependencies: dependencies, - Properties: apiSetToProperties(providedAPIs, nil, deprecated), + Properties: properties, }, - dependencies: dependencies, - properties: apiSetToProperties(providedAPIs, nil, deprecated), + properties: properties, sourceInfo: &OperatorSourceInfo{ Catalog: registry.CatalogKey{ Name: catalogName, @@ -1490,6 +1500,46 @@ func TestSolveOperators_WithSkips(t *testing.T) { require.EqualValues(t, expected, operators) } +func TestSolveOperatorsWithClusterServiceVersionHavingDependency(t *testing.T) { + const namespace = "test-namespace" + catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} + + a1 := existingOperator(namespace, "a-1", "a", "default", "", nil, nil, nil, nil) + a1.Annotations = map[string]string{ + "operatorframework.io/properties": `{"properties":[{"type":"olm.package.required","value":{"packageName":"b","versionRange":"1.0.0"}}]}`, + } + + b1 := existingOperator(namespace, "b-1", "b", "default", "", nil, nil, nil, nil) + b1.Annotations = map[string]string{ + "operatorframework.io/properties": `{"properties":[{"type":"olm.package","value":{"packageName":"b","version":"1.0.0"}}]}`, + } + + csvs := []*v1alpha1.ClusterServiceVersion{a1, b1} + subs := []*v1alpha1.Subscription{ + existingSub(namespace, "b-1", "b", "default", catalog), + } + + log, _ := test.NewNullLogger() + r := SatResolver{ + cache: getFakeOperatorCache(NamespacedOperatorCache{ + snapshots: map[registry.CatalogKey]*CatalogSnapshot{ + catalog: { + key: catalog, + operators: []*Operator{ + genOperator("b-2", "2.0.0", "b-1", "b", "default", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + }, + }, + }, + }), + log: log, + } + + operators, err := r.SolveOperators([]string{namespace}, csvs, subs) + assert.NoError(t, err) + //expected := OperatorSet{} + require.Empty(t, operators) +} + func TestInferProperties(t *testing.T) { catalog := registry.CatalogKey{Namespace: "namespace", Name: "name"} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go index 1fd00375f3..0c017c7cc5 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/installabletypes.go @@ -60,24 +60,30 @@ func NewBundleInstallableFromOperator(o *Operator) (BundleInstallable, error) { if src == nil { return BundleInstallable{}, fmt.Errorf("unable to resolve the source of bundle %s", o.Identifier()) } + id := bundleId(o.Identifier(), o.Channel(), src.Catalog) var constraints []solver.Constraint + if src.Catalog.Virtual() && src.Subscription == nil { + // CSVs already associated with a Subscription + // may be replaced, but freestanding CSVs must + // appear in any solution. + constraints = append(constraints, PrettyConstraint( + solver.Mandatory(), + fmt.Sprintf("clusterserviceversion %s exists and is not referenced by a subscription", o.Identifier()), + )) + } for _, p := range o.bundle.GetProperties() { if p.GetType() == operatorregistry.DeprecatedType { constraints = append(constraints, PrettyConstraint( solver.Prohibited(), - fmt.Sprintf("bundle %s is deprecated", bundleId(o.Identifier(), o.Channel(), src.Catalog)), + fmt.Sprintf("bundle %s is deprecated", id), )) break } } - return NewBundleInstallable(o.Identifier(), o.Channel(), src.Catalog, constraints...), nil -} - -func NewBundleInstallable(bundle, channel string, catalog registry.CatalogKey, constraints ...solver.Constraint) BundleInstallable { return BundleInstallable{ - identifier: bundleId(bundle, channel, catalog), + identifier: id, constraints: constraints, - } + }, nil } type GenericInstallable struct { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go index 19a0b933ed..1c21425bf2 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/operators.go @@ -11,10 +11,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-registry/pkg/api" opregistry "github.com/operator-framework/operator-registry/pkg/registry" - - "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" ) type APISet map[opregistry.APIKey]struct{} @@ -197,6 +196,7 @@ type OperatorSourceInfo struct { StartingCSV string Catalog registry.CatalogKey DefaultChannel bool + Subscription *v1alpha1.Subscription } func (i *OperatorSourceInfo) String() string { @@ -216,7 +216,6 @@ type OperatorSurface interface { SourceInfo() *OperatorSourceInfo Bundle() *api.Bundle Inline() bool - Dependencies() []*api.Dependency Properties() []*api.Property Skips() []string } @@ -229,7 +228,6 @@ type Operator struct { version *semver.Version bundle *api.Bundle sourceInfo *OperatorSourceInfo - dependencies []*api.Dependency properties []*api.Property skips []string } @@ -261,21 +259,27 @@ func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey reg // legacy support - if the api doesn't contain properties/dependencies, build them from required/provided apis properties := bundle.Properties if len(properties) == 0 { - properties, err = apisToProperties(provided) + properties, err = providedAPIsToProperties(provided) if err != nil { return nil, err } } - dependencies := bundle.Dependencies - if len(dependencies) == 0 { - dependencies, err = apisToDependencies(required) + if len(bundle.Dependencies) > 0 { + ps, err := legacyDependenciesToProperties(bundle.Dependencies) + if err != nil { + return nil, fmt.Errorf("failed to translate legacy dependencies to properties: %w", err) + } + properties = append(properties, ps...) + } else { + ps, err := requiredAPIsToProperties(required) if err != nil { return nil, err } + properties = append(properties, ps...) } // legacy support - if the grpc api doesn't contain required/provided apis, fallback to csv parsing - if len(required) == 0 && len(provided) == 0 && len(properties) == 0 && len(dependencies) == 0 { + if len(required) == 0 && len(provided) == 0 && len(properties) == 0 { // fallback to csv parsing if bundle.CsvJson == "" { if bundle.GetBundlePath() != "" { @@ -307,7 +311,6 @@ func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey reg requiredAPIs: required, bundle: bundle, sourceInfo: sourceInfo, - dependencies: dependencies, properties: properties, skips: bundle.Skips, }, nil @@ -338,15 +341,15 @@ func NewOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*Operator, requiredAPIs[opregistry.APIKey{Group: api.Group, Version: api.Version, Kind: api.Kind, Plural: api.Name}] = struct{}{} } - dependencies, err := apisToDependencies(requiredAPIs) + properties, err := providedAPIsToProperties(providedAPIs) if err != nil { return nil, err } - - properties, err := apisToProperties(providedAPIs) + dependencies, err := requiredAPIsToProperties(requiredAPIs) if err != nil { return nil, err } + properties = append(properties, dependencies...) return &Operator{ name: csv.GetName(), @@ -354,7 +357,6 @@ func NewOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*Operator, providedAPIs: providedAPIs, requiredAPIs: requiredAPIs, sourceInfo: &ExistingOperator, - dependencies: dependencies, properties: properties, }, nil } @@ -413,48 +415,48 @@ func (o *Operator) Inline() bool { return o.bundle != nil && o.bundle.GetBundlePath() == "" } -func (o *Operator) Dependencies() []*api.Dependency { - return o.dependencies -} - func (o *Operator) Properties() []*api.Property { return o.properties } func (o *Operator) DependencyPredicates() (predicates []OperatorPredicate, err error) { predicates = make([]OperatorPredicate, 0) - for _, d := range o.Dependencies() { - var p OperatorPredicate - if d == nil || d.Type == "" { - continue - } - p, err = PredicateForDependency(d) + for _, property := range o.Properties() { + predicate, err := PredicateForProperty(property) if err != nil { - return + return nil, err + } + if predicate == nil { + continue } - predicates = append(predicates, p) + predicates = append(predicates, predicate) } return } -// TODO: this should go in its own dependency/predicate builder package -// TODO: can we make this more extensible, i.e. via cue -func PredicateForDependency(dependency *api.Dependency) (OperatorPredicate, error) { - p, ok := predicates[dependency.Type] +func PredicateForProperty(property *api.Property) (OperatorPredicate, error) { + if property == nil { + return nil, nil + } + p, ok := predicates[property.Type] if !ok { - return nil, fmt.Errorf("no predicate for dependency type %s", dependency.Type) + return nil, nil } - return p(dependency.Value) + return p(property.Value) } var predicates = map[string]func(string) (OperatorPredicate, error){ - opregistry.GVKType: predicateForGVKDependency, - opregistry.PackageType: predicateForPackageDependency, - opregistry.LabelType: predicateForLabelDependency, + "olm.gvk.required": predicateForRequiredGVKProperty, + "olm.package.required": predicateForRequiredPackageProperty, + "olm.label.required": predicateForRequiredLabelProperty, } -func predicateForGVKDependency(value string) (OperatorPredicate, error) { - var gvk opregistry.GVKDependency +func predicateForRequiredGVKProperty(value string) (OperatorPredicate, error) { + var gvk struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + } if err := json.Unmarshal([]byte(value), &gvk); err != nil { return nil, err } @@ -465,44 +467,51 @@ func predicateForGVKDependency(value string) (OperatorPredicate, error) { }), nil } -func predicateForPackageDependency(value string) (OperatorPredicate, error) { - var pkg opregistry.PackageDependency +func predicateForRequiredPackageProperty(value string) (OperatorPredicate, error) { + var pkg struct { + PackageName string `json:"packageName"` + VersionRange string `json:"versionRange"` + } if err := json.Unmarshal([]byte(value), &pkg); err != nil { return nil, err } - ver, err := semver.ParseRange(pkg.Version) + ver, err := semver.ParseRange(pkg.VersionRange) if err != nil { return nil, err } - return And(WithPackage(pkg.PackageName), WithVersionInRange(ver)), nil } -func predicateForLabelDependency(value string) (OperatorPredicate, error) { - var label opregistry.LabelDependency +func predicateForRequiredLabelProperty(value string) (OperatorPredicate, error) { + var label struct { + Label string `json:"label"` + } if err := json.Unmarshal([]byte(value), &label); err != nil { return nil, err } - return WithLabel(label.Label), nil } -func apisToDependencies(apis APISet) (out []*api.Dependency, err error) { +func requiredAPIsToProperties(apis APISet) (out []*api.Property, err error) { if len(apis) == 0 { return } - out = make([]*api.Dependency, 0) + out = make([]*api.Property, 0) for a := range apis { - val, err := json.Marshal(opregistry.GVKDependency{ + val, err := json.Marshal(struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + }{ Group: a.Group, - Kind: a.Kind, Version: a.Version, + Kind: a.Kind, }) if err != nil { return nil, err } - out = append(out, &api.Dependency{ - Type: opregistry.GVKType, + out = append(out, &api.Property{ + Type: "olm.gvk.required", Value: string(val), }) } @@ -512,13 +521,13 @@ func apisToDependencies(apis APISet) (out []*api.Dependency, err error) { return nil, nil } -func apisToProperties(apis APISet) (out []*api.Property, err error) { +func providedAPIsToProperties(apis APISet) (out []*api.Property, err error) { out = make([]*api.Property, 0) for a := range apis { val, err := json.Marshal(opregistry.GVKProperty{ Group: a.Group, - Kind: a.Kind, Version: a.Version, + Kind: a.Kind, }) if err != nil { panic(err) @@ -533,3 +542,63 @@ func apisToProperties(apis APISet) (out []*api.Property, err error) { } return nil, nil } + +func legacyDependenciesToProperties(dependencies []*api.Dependency) ([]*api.Property, error) { + var result []*api.Property + for _, dependency := range dependencies { + switch dependency.Type { + case "olm.gvk": + type gvk struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` + } + var vfrom gvk + if err := json.Unmarshal([]byte(dependency.Value), &vfrom); err != nil { + return nil, fmt.Errorf("failed to unmarshal legacy 'olm.gvk' dependency: %w", err) + } + vto := gvk{ + Group: vfrom.Group, + Version: vfrom.Version, + Kind: vfrom.Kind, + } + vb, err := json.Marshal(&vto) + if err != nil { + return nil, fmt.Errorf("unexpected error marshaling generated 'olm.package.required' property: %w", err) + } + result = append(result, &api.Property{ + Type: "olm.gvk.required", + Value: string(vb), + }) + case "olm.package": + var vfrom struct { + PackageName string `json:"packageName"` + VersionRange string `json:"version"` + } + if err := json.Unmarshal([]byte(dependency.Value), &vfrom); err != nil { + return nil, fmt.Errorf("failed to unmarshal legacy 'olm.package' dependency: %w", err) + } + vto := struct { + PackageName string `json:"packageName"` + VersionRange string `json:"versionRange"` + }{ + PackageName: vfrom.PackageName, + VersionRange: vfrom.VersionRange, + } + vb, err := json.Marshal(&vto) + if err != nil { + return nil, fmt.Errorf("unexpected error marshaling generated 'olm.package.required' property: %w", err) + } + result = append(result, &api.Property{ + Type: "olm.package.required", + Value: string(vb), + }) + case "olm.label": + result = append(result, &api.Property{ + Type: "olm.label.required", + Value: dependency.Value, + }) + } + } + return result, nil +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index e2ee4a66e0..a4473f36bf 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -55,12 +55,16 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust startingCSVs := make(map[string]struct{}) // build a virtual catalog of all currently installed CSVs - existingSnapshot, existingInstallables, err := r.newSnapshotForNamespace(namespaces[0], subs, csvs) + existingSnapshot, err := r.newSnapshotForNamespace(namespaces[0], subs, csvs) if err != nil { return nil, err } namespacedCache := r.cache.Namespaced(namespaces...).WithExistingOperators(existingSnapshot) + _, existingInstallables, err := r.getBundleInstallables(registry.NewVirtualCatalogKey(namespaces[0]), existingSnapshot.Find(), namespacedCache, visited) + if err != nil { + return nil, err + } for _, i := range existingInstallables { installables[i.Identifier()] = i } @@ -248,7 +252,8 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu candidates := make([]*BundleInstallable, 0) for _, o := range Filter(sortedBundles, channelPredicates...) { predicates := append(cachePredicates, WithCSVName(o.Identifier())) - id, installable, err := r.getBundleInstallables(catalog, predicates, namespacedCache, visited) + stack := namespacedCache.Catalog(catalog).Find(predicates...) + id, installable, err := r.getBundleInstallables(catalog, stack, namespacedCache, visited) if err != nil { return nil, err } @@ -292,17 +297,10 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu return installables, nil } -func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, predicates []OperatorPredicate, namespacedCache MultiCatalogOperatorFinder, visited map[OperatorSurface]*BundleInstallable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleInstallable, error) { +func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, bundleStack []*Operator, namespacedCache MultiCatalogOperatorFinder, visited map[OperatorSurface]*BundleInstallable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleInstallable, error) { errs := make([]error, 0) installables := make(map[solver.Identifier]*BundleInstallable, 0) // all installables, including dependencies - var finder OperatorFinder = namespacedCache - if !catalog.Empty() { - finder = namespacedCache.Catalog(catalog) - } - - bundleStack := finder.Find(predicates...) - // track the first layer of installable ids var initial = make(map[*Operator]struct{}) for _, o := range bundleStack { @@ -353,11 +351,18 @@ func (r *SatResolver) getBundleInstallables(catalog registry.CatalogKey, predica } sources[*si] = struct{}{} - sourcePredicate = Or(sourcePredicate, And( - WithPackage(si.Package), - WithChannel(si.Channel), - WithCatalog(si.Catalog), - )) + if si.Catalog.Virtual() { + sourcePredicate = Or(sourcePredicate, And( + WithCSVName(b.Identifier()), + WithCatalog(si.Catalog), + )) + } else { + sourcePredicate = Or(sourcePredicate, And( + WithPackage(si.Package), + WithChannel(si.Channel), + WithCatalog(si.Catalog), + )) + } } sortedBundles, err := r.sortBundles(namespacedCache.FindPreferred(&bundle.sourceInfo.Catalog, sourcePredicate)) if err != nil { @@ -441,15 +446,14 @@ func (r *SatResolver) inferProperties(csv *v1alpha1.ClusterServiceVersion, subs return properties, nil } -func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1.Subscription, csvs []*v1alpha1.ClusterServiceVersion) (*CatalogSnapshot, []solver.Installable, error) { - installables := make([]solver.Installable, 0) +func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1.Subscription, csvs []*v1alpha1.ClusterServiceVersion) (*CatalogSnapshot, error) { existingOperatorCatalog := registry.NewVirtualCatalogKey(namespace) // build a catalog snapshot of CSVs without subscriptions - csvsWithSubscriptions := make(map[*v1alpha1.ClusterServiceVersion]struct{}) + csvSubscriptions := make(map[*v1alpha1.ClusterServiceVersion]*v1alpha1.Subscription) for _, sub := range subs { for _, csv := range csvs { if csv.Name == sub.Status.InstalledCSV { - csvsWithSubscriptions[csv] = struct{}{} + csvSubscriptions[csv] = sub break } } @@ -457,17 +461,9 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 var csvsMissingProperties []*v1alpha1.ClusterServiceVersion standaloneOperators := make([]*Operator, 0) for _, csv := range csvs { - var constraints []solver.Constraint - if _, ok := csvsWithSubscriptions[csv]; !ok { - // CSVs already associated with a Subscription - // may be replaced, but freestanding CSVs must - // appear in any solution. - constraints = append(constraints, solver.Mandatory()) - } - op, err := NewOperatorFromV1Alpha1CSV(csv) if err != nil { - return nil, nil, err + return nil, err } if anno, ok := csv.GetAnnotations()[projection.PropertiesAnnotationKey]; !ok { @@ -478,13 +474,14 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 op.properties = append(op.properties, inferred...) } } else if props, err := projection.PropertyListFromPropertiesAnnotation(anno); err != nil { - return nil, nil, fmt.Errorf("failed to retrieve properties of csv %q: %w", csv.GetName(), err) + return nil, fmt.Errorf("failed to retrieve properties of csv %q: %w", csv.GetName(), err) } else { op.properties = props } op.sourceInfo = &OperatorSourceInfo{ - Catalog: existingOperatorCatalog, + Catalog: existingOperatorCatalog, + Subscription: csvSubscriptions[csv], } // Try to determine source package name from properties and add to SourceInfo. for _, p := range op.properties { @@ -501,10 +498,6 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 } standaloneOperators = append(standaloneOperators, op) - - // all standalone operators are mandatory - i := NewBundleInstallable(op.Identifier(), "", existingOperatorCatalog, constraints...) - installables = append(installables, &i) } if len(csvsMissingProperties) > 0 { @@ -515,7 +508,7 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1 r.log.Infof("considered csvs without properties annotation during resolution: %v", names) } - return NewRunningOperatorSnapshot(r.log, existingOperatorCatalog, standaloneOperators), installables, nil + return NewRunningOperatorSnapshot(r.log, existingOperatorCatalog, standaloneOperators), nil } func (r *SatResolver) addInvariants(namespacedCache MultiCatalogOperatorFinder, installables map[solver.Identifier]solver.Installable) { From 0745028cb521b9da908b59e00f67233b951dd3f0 Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 18 Jun 2021 10:39:50 -0400 Subject: [PATCH 05/30] Use one HTTP server for healthz, metrics, and profiling. TLS can still be enabled via flags, but it now applies to all three APIs since there is a single HTTP server per operator process. The -profiling flag is deprecated and does nothing. The profiling APIs are now always enabled, but they refuse to serve clients that do not present a verifiable certificate (see the new flag -client-ca). This effectively disables the profiling APIs when served over HTTP. Co-authored-by: Vu Dinh Co-authored-by: Alexander Greene Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: f9381e0ce8e0addeb1abf55d44146a5e6e57074a --- manifests/0000_50_olm_02-services.yaml | 8 +- ...operator.deployment.ibm-cloud-managed.yaml | 43 +++++++---- ...000_50_olm_07-olm-operator.deployment.yaml | 43 +++++++---- ...operator.deployment.ibm-cloud-managed.yaml | 47 +++++++---- ...50_olm_08-catalog-operator.deployment.yaml | 47 +++++++---- .../cmd/catalog/main.go | 67 +++------------- .../cmd/olm/main.go | 68 +++------------- .../templates/0000_50_olm_02-services.yaml | 8 +- ...000_50_olm_07-olm-operator.deployment.yaml | 43 +++++++++-- ...50_olm_08-catalog-operator.deployment.yaml | 45 ++++++++--- .../deploy/chart/values.yaml | 6 ++ .../pkg/lib/filemonitor/cabundle_updater.go | 60 +++++++++++++++ .../pkg/lib/filemonitor/cert_updater.go | 41 +++------- .../pkg/lib/filemonitor/cert_updater_test.go | 16 +++- .../pkg/lib/filemonitor/watcher.go | 6 +- .../pkg/lib/profile/profile.go | 20 +++-- .../pkg/lib/server/server.go | 77 +++++++++++++++++++ .../test/e2e/installplan_e2e_test.go | 4 +- .../test/e2e/metrics_e2e_test.go | 26 +++---- values.yaml | 14 +++- .../cmd/catalog/main.go | 67 +++------------- .../cmd/olm/main.go | 68 +++------------- .../pkg/lib/filemonitor/cabundle_updater.go | 60 +++++++++++++++ .../pkg/lib/filemonitor/cert_updater.go | 41 +++------- .../pkg/lib/filemonitor/watcher.go | 6 +- .../pkg/lib/profile/profile.go | 20 +++-- .../pkg/lib/server/server.go | 77 +++++++++++++++++++ vendor/modules.txt | 1 + 28 files changed, 611 insertions(+), 418 deletions(-) create mode 100644 staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go create mode 100644 staging/operator-lifecycle-manager/pkg/lib/server/server.go create mode 100644 vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go create mode 100644 vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server/server.go diff --git a/manifests/0000_50_olm_02-services.yaml b/manifests/0000_50_olm_02-services.yaml index d82d2b8a87..a57315d5bd 100644 --- a/manifests/0000_50_olm_02-services.yaml +++ b/manifests/0000_50_olm_02-services.yaml @@ -14,9 +14,9 @@ spec: type: ClusterIP ports: - name: https-metrics - port: 8081 + port: 8443 protocol: TCP - targetPort: metrics + targetPort: 8443 selector: app: olm-operator --- @@ -36,8 +36,8 @@ spec: type: ClusterIP ports: - name: https-metrics - port: 8081 + port: 8443 protocol: TCP - targetPort: metrics + targetPort: 8443 selector: app: catalog-operator diff --git a/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml b/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml index 57f5b9d2bf..35e85add38 100644 --- a/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml +++ b/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml @@ -22,8 +22,27 @@ spec: target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' spec: serviceAccountName: olm-operator-serviceaccount + volumes: + - name: srv-cert + secret: + secretName: olm-operator-serving-cert + - name: profile-collector-cert + secret: + secretName: olm-operator-serving-cert + - name: serving-cert + secret: + secretName: olm-operator-serving-cert containers: - name: olm-operator + volumeMounts: + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + - mountPath: /var/run/secrets/serving-cert + name: serving-cert command: - /bin/olm args: @@ -34,24 +53,25 @@ spec: - --writePackageServerStatusName - operator-lifecycle-manager-packageserver - --tls-cert - - /var/run/secrets/serving-cert/tls.crt + - /srv-cert/tls.crt - --tls-key - - /var/run/secrets/serving-cert/tls.key + - /srv-cert/tls.key + - --client-ca + - /profile-collector-cert/tls.crt image: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 imagePullPolicy: IfNotPresent ports: - - containerPort: 8080 - - containerPort: 8081 - name: metrics - protocol: TCP + - containerPort: 8443 livenessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS readinessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS terminationMessagePolicy: FallbackToLogsOnError env: - name: OPERATOR_NAMESPACE @@ -66,9 +86,6 @@ spec: requests: cpu: 10m memory: 160Mi - volumeMounts: - - mountPath: /var/run/secrets/serving-cert - name: serving-cert nodeSelector: kubernetes.io/os: linux tolerations: @@ -84,7 +101,3 @@ spec: operator: Exists tolerationSeconds: 120 priorityClassName: system-cluster-critical - volumes: - - name: serving-cert - secret: - secretName: olm-operator-serving-cert diff --git a/manifests/0000_50_olm_07-olm-operator.deployment.yaml b/manifests/0000_50_olm_07-olm-operator.deployment.yaml index e2f013a6c3..139bac5339 100644 --- a/manifests/0000_50_olm_07-olm-operator.deployment.yaml +++ b/manifests/0000_50_olm_07-olm-operator.deployment.yaml @@ -23,8 +23,27 @@ spec: target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' spec: serviceAccountName: olm-operator-serviceaccount + volumes: + - name: srv-cert + secret: + secretName: olm-operator-serving-cert + - name: profile-collector-cert + secret: + secretName: olm-operator-serving-cert + - name: serving-cert + secret: + secretName: olm-operator-serving-cert containers: - name: olm-operator + volumeMounts: + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + - mountPath: /var/run/secrets/serving-cert + name: serving-cert command: - /bin/olm args: @@ -35,24 +54,25 @@ spec: - --writePackageServerStatusName - operator-lifecycle-manager-packageserver - --tls-cert - - /var/run/secrets/serving-cert/tls.crt + - /srv-cert/tls.crt - --tls-key - - /var/run/secrets/serving-cert/tls.key + - /srv-cert/tls.key + - --client-ca + - /profile-collector-cert/tls.crt image: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 imagePullPolicy: IfNotPresent ports: - - containerPort: 8080 - - containerPort: 8081 - name: metrics - protocol: TCP + - containerPort: 8443 livenessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS readinessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS terminationMessagePolicy: FallbackToLogsOnError env: - name: OPERATOR_NAMESPACE @@ -67,9 +87,6 @@ spec: requests: cpu: 10m memory: 160Mi - volumeMounts: - - mountPath: /var/run/secrets/serving-cert - name: serving-cert nodeSelector: kubernetes.io/os: linux node-role.kubernetes.io/master: "" @@ -86,7 +103,3 @@ spec: operator: Exists tolerationSeconds: 120 priorityClassName: system-cluster-critical - volumes: - - name: serving-cert - secret: - secretName: olm-operator-serving-cert diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml index eb80db2297..0b1812f1ca 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml @@ -22,8 +22,27 @@ spec: target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' spec: serviceAccountName: olm-operator-serviceaccount + volumes: + - name: srv-cert + secret: + secretName: catalog-operator-serving-cert + - name: profile-collector-cert + secret: + secretName: catalog-operator-serving-cert + - name: serving-cert + secret: + secretName: catalog-operator-serving-cert containers: - name: catalog-operator + volumeMounts: + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + - mountPath: /var/run/secrets/serving-cert + name: serving-cert command: - /bin/catalog args: @@ -34,25 +53,26 @@ spec: - quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 - -writeStatusName - operator-lifecycle-manager-catalog - - -tls-cert - - /var/run/secrets/serving-cert/tls.crt - - -tls-key - - /var/run/secrets/serving-cert/tls.key + - --tls-cert + - /srv-cert/tls.crt + - --tls-key + - /srv-cert/tls.key + - --client-ca + - /profile-collector-cert/tls.crt image: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 imagePullPolicy: IfNotPresent ports: - - containerPort: 8080 - - containerPort: 8081 - name: metrics - protocol: TCP + - containerPort: 8443 livenessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS readinessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS terminationMessagePolicy: FallbackToLogsOnError resources: requests: @@ -61,9 +81,6 @@ spec: env: - name: RELEASE_VERSION value: "0.0.1-snapshot" - volumeMounts: - - mountPath: /var/run/secrets/serving-cert - name: serving-cert nodeSelector: kubernetes.io/os: linux tolerations: @@ -79,7 +96,3 @@ spec: operator: Exists tolerationSeconds: 120 priorityClassName: system-cluster-critical - volumes: - - name: serving-cert - secret: - secretName: catalog-operator-serving-cert diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml index 901bf0df8f..903a94ee9b 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml @@ -23,8 +23,27 @@ spec: target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' spec: serviceAccountName: olm-operator-serviceaccount + volumes: + - name: srv-cert + secret: + secretName: catalog-operator-serving-cert + - name: profile-collector-cert + secret: + secretName: catalog-operator-serving-cert + - name: serving-cert + secret: + secretName: catalog-operator-serving-cert containers: - name: catalog-operator + volumeMounts: + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + - mountPath: /var/run/secrets/serving-cert + name: serving-cert command: - /bin/catalog args: @@ -35,25 +54,26 @@ spec: - quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 - -writeStatusName - operator-lifecycle-manager-catalog - - -tls-cert - - /var/run/secrets/serving-cert/tls.crt - - -tls-key - - /var/run/secrets/serving-cert/tls.key + - --tls-cert + - /srv-cert/tls.crt + - --tls-key + - /srv-cert/tls.key + - --client-ca + - /profile-collector-cert/tls.crt image: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 imagePullPolicy: IfNotPresent ports: - - containerPort: 8080 - - containerPort: 8081 - name: metrics - protocol: TCP + - containerPort: 8443 livenessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS readinessProbe: httpGet: path: /healthz - port: 8080 + port: 8443 + scheme: HTTPS terminationMessagePolicy: FallbackToLogsOnError resources: requests: @@ -62,9 +82,6 @@ spec: env: - name: RELEASE_VERSION value: "0.0.1-snapshot" - volumeMounts: - - mountPath: /var/run/secrets/serving-cert - name: serving-cert nodeSelector: kubernetes.io/os: linux node-role.kubernetes.io/master: "" @@ -81,7 +98,3 @@ spec: operator: Exists tolerationSeconds: 120 priorityClassName: system-cluster-critical - volumes: - - name: serving-cert - secret: - secretName: catalog-operator-serving-cert diff --git a/staging/operator-lifecycle-manager/cmd/catalog/main.go b/staging/operator-lifecycle-manager/cmd/catalog/main.go index 4f945eb008..805334efbb 100644 --- a/staging/operator-lifecycle-manager/cmd/catalog/main.go +++ b/staging/operator-lifecycle-manager/cmd/catalog/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "crypto/tls" "flag" "fmt" "net/http" @@ -10,7 +9,6 @@ import ( "time" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" utilclock "k8s.io/apimachinery/pkg/util/clock" k8sscheme "k8s.io/client-go/kubernetes/scheme" @@ -18,10 +16,9 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals" "github.com/operator-framework/operator-lifecycle-manager/pkg/metrics" olmversion "github.com/operator-framework/operator-lifecycle-manager/pkg/version" @@ -67,8 +64,9 @@ var ( tlsCertPath = flag.String( "tls-cert", "", "Path to use for certificate key (requires tls-key)") - profiling = flag.Bool( - "profiling", false, "serve profiling data (on port 8080)") + profiling = flag.Bool("profiling", false, "deprecated") + + clientCAPath = flag.String("client-ca", "", "path to watch for client ca bundle") installPlanTimeout = flag.Duration("install-plan-retry-timeout", 1*time.Minute, "time since first attempt at which plan execution errors are considered fatal") bundleUnpackTimeout = flag.Duration("bundle-unpack-timeout", 10*time.Minute, "The time limit for bundle unpacking, after which InstallPlan execution is considered to have failed. 0 is considered as having no timeout.") @@ -106,59 +104,16 @@ func main() { *catalogNamespace = catalogNamespaceEnvVarValue } - var useTLS bool - if *tlsCertPath != "" && *tlsKeyPath == "" || *tlsCertPath == "" && *tlsKeyPath != "" { - logger.Warn("both --tls-key and --tls-crt must be provided for TLS to be enabled, falling back to non-https") - } else if *tlsCertPath == "" && *tlsKeyPath == "" { - logger.Info("TLS keys not set, using non-https for metrics") - } else { - logger.Info("TLS keys set, using https for metrics") - useTLS = true - } - - // Serve a health check. - healthMux := http.NewServeMux() - healthMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - // Serve profiling if enabled - if *profiling { - logger.Infof("profiling enabled") - profile.RegisterHandlers(healthMux) + listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath) + if err != nil { + logger.Fatal("Error setting up health/metric/pprof service: %v", err) } - go http.ListenAndServe(":8080", healthMux) - - metricsMux := http.NewServeMux() - metricsMux.Handle("/metrics", promhttp.Handler()) - if useTLS { - tlsGetCertFn, err := filemonitor.OLMGetCertRotationFn(logger, *tlsCertPath, *tlsKeyPath) - if err != nil { - logger.Errorf("Certificate monitoring for metrics (https) failed: %v", err) + go func() { + if err := listenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Error(err) } - - go func() { - httpsServer := &http.Server{ - Addr: ":8081", - Handler: metricsMux, - TLSConfig: &tls.Config{ - GetCertificate: tlsGetCertFn, - }, - } - err := httpsServer.ListenAndServeTLS("", "") - if err != nil { - logger.Errorf("Metrics (https) serving failed: %v", err) - } - }() - } else { - go func() { - err := http.ListenAndServe(":8081", metricsMux) - if err != nil { - logger.Errorf("Metrics (http) serving failed: %v", err) - } - }() - } + }() // create a config client for operator status config, err := clientcmd.BuildConfigFromFlags("", *kubeConfigPath) diff --git a/staging/operator-lifecycle-manager/cmd/olm/main.go b/staging/operator-lifecycle-manager/cmd/olm/main.go index 087ebb74a8..f9bec9f689 100644 --- a/staging/operator-lifecycle-manager/cmd/olm/main.go +++ b/staging/operator-lifecycle-manager/cmd/olm/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "crypto/tls" "flag" "fmt" "net/http" @@ -12,7 +11,6 @@ import ( configclientset "github.com/openshift/client-go/config/clientset/versioned" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" "github.com/spf13/pflag" v1 "k8s.io/api/core/v1" @@ -23,11 +21,10 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift" "github.com/operator-framework/operator-lifecycle-manager/pkg/feature" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals" "github.com/operator-framework/operator-lifecycle-manager/pkg/metrics" olmversion "github.com/operator-framework/operator-lifecycle-manager/pkg/version" @@ -66,8 +63,9 @@ var ( tlsCertPath = pflag.String( "tls-cert", "", "Path to use for certificate key (requires tls-key)") - profiling = pflag.Bool( - "profiling", false, "serve profiling data (on port 8080)") + profiling = pflag.Bool("profiling", false, "deprecated") + + clientCAPath = pflag.String("client-ca", "", "path to watch for client ca bundle") namespace = pflag.String( "namespace", "", "namespace where cleanup runs") @@ -120,65 +118,17 @@ func main() { } logger.Infof("log level %s", logger.Level) - var useTLS bool - if *tlsCertPath != "" && *tlsKeyPath == "" || *tlsCertPath == "" && *tlsKeyPath != "" { - logger.Warn("both --tls-key and --tls-crt must be provided for TLS to be enabled, falling back to non-https") - } else if *tlsCertPath == "" && *tlsKeyPath == "" { - logger.Info("TLS keys not set, using non-https for metrics") - } else { - logger.Info("TLS keys set, using https for metrics") - useTLS = true - } - - // Serve a health check. - healthMux := http.NewServeMux() - healthMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - // Serve profiling if enabled - if *profiling { - logger.Infof("profiling enabled") - profile.RegisterHandlers(healthMux) + listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath) + if err != nil { + logger.Fatal("Error setting up health/metric/pprof service: %v", err) } go func() { - err := http.ListenAndServe(":8080", healthMux) - if err != nil { - logger.Errorf("Health serving failed: %v", err) + if err := listenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Error(err) } }() - metricsMux := http.NewServeMux() - metricsMux.Handle("/metrics", promhttp.Handler()) - if useTLS { - tlsGetCertFn, err := filemonitor.OLMGetCertRotationFn(logger, *tlsCertPath, *tlsKeyPath) - if err != nil { - logger.Errorf("Certificate monitoring for metrics (https) failed: %v", err) - } - - go func() { - httpsServer := &http.Server{ - Addr: ":8081", - Handler: metricsMux, - TLSConfig: &tls.Config{ - GetCertificate: tlsGetCertFn, - }, - } - err := httpsServer.ListenAndServeTLS("", "") - if err != nil { - logger.Errorf("Metrics (https) serving failed: %v", err) - } - }() - } else { - go func() { - err := http.ListenAndServe(":8081", metricsMux) - if err != nil { - logger.Errorf("Metrics (http) serving failed: %v", err) - } - }() - } - mgr, err := Manager(ctx, *debug) if err != nil { logger.WithError(err).Fatalf("error configuring controller manager") diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_02-services.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_02-services.yaml index 923cdaccec..51fb8df0e3 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_02-services.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_02-services.yaml @@ -12,9 +12,9 @@ spec: type: ClusterIP ports: - name: https-metrics - port: 8081 + port: {{ .Values.olm.service.externalPort }} protocol: TCP - targetPort: metrics + targetPort: {{ .Values.olm.service.internalPort }} selector: app: olm-operator --- @@ -31,9 +31,9 @@ spec: type: ClusterIP ports: - name: https-metrics - port: 8081 + port: {{ .Values.catalog.service.externalPort }} protocol: TCP - targetPort: metrics + targetPort: {{ .Values.catalog.service.internalPort }} selector: app: catalog-operator {{ end }} diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml index 7225c10ae8..2fac21b4db 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml @@ -18,8 +18,34 @@ spec: app: olm-operator spec: serviceAccountName: olm-operator-serviceaccount + {{- if or .Values.olm.tlsSecret .Values.olm.clientCASecret }} + volumes: + {{- end }} + {{- if .Values.olm.tlsSecret }} + - name: srv-cert + secret: + secretName: {{ .Values.olm.tlsSecret }} + {{- end }} + {{- if .Values.olm.clientCASecret }} + - name: profile-collector-cert + secret: + secretName: {{ .Values.olm.clientCASecret }} + {{- end }} containers: - name: olm-operator + {{- if or .Values.olm.tlsSecret .Values.olm.clientCASecret }} + volumeMounts: + {{- end }} + {{- if .Values.olm.tlsSecret }} + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + {{- end }} + {{- if .Values.olm.clientCASecret }} + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + {{- end }} command: - /bin/olm args: @@ -43,29 +69,30 @@ spec: - --writePackageServerStatusName - {{ .Values.writePackageServerStatusName }} {{- end }} - {{- if .Values.olm.tlsCertPath }} + {{- if .Values.olm.tlsSecret }} - --tls-cert - - {{ .Values.olm.tlsCertPath }} - {{- end }} - {{- if .Values.olm.tlsKeyPath }} + - /srv-cert/tls.crt - --tls-key - - {{ .Values.olm.tlsKeyPath }} + - /srv-cert/tls.key + {{- end }} + {{- if .Values.olm.clientCASecret }} + - --client-ca + - /profile-collector-cert/tls.crt {{- end }} image: {{ .Values.olm.image.ref }} imagePullPolicy: {{ .Values.olm.image.pullPolicy }} ports: - containerPort: {{ .Values.olm.service.internalPort }} - - containerPort: 8081 - name: metrics - protocol: TCP livenessProbe: httpGet: path: /healthz port: {{ .Values.olm.service.internalPort }} + scheme: {{ if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}HTTPS{{ else }}HTTP{{end}} readinessProbe: httpGet: path: /healthz port: {{ .Values.olm.service.internalPort }} + scheme: {{ if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}HTTPS{{ else }}HTTP{{end}} terminationMessagePolicy: FallbackToLogsOnError env: - name: OPERATOR_NAMESPACE diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml index ab1a36166b..0af5686967 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml @@ -18,8 +18,34 @@ spec: app: catalog-operator spec: serviceAccountName: olm-operator-serviceaccount + {{- if or .Values.catalog.tlsSecret .Values.catalog.clientCASecret }} + volumes: + {{- end }} + {{- if .Values.catalog.tlsSecret }} + - name: srv-cert + secret: + secretName: {{ .Values.catalog.tlsSecret }} + {{- end }} + {{- if .Values.catalog.clientCASecret }} + - name: profile-collector-cert + secret: + secretName: {{ .Values.catalog.clientCASecret }} + {{- end }} containers: - name: catalog-operator + {{- if or .Values.catalog.tlsSecret .Values.catalog.clientCASecret }} + volumeMounts: + {{- end }} + {{- if .Values.catalog.tlsSecret }} + - name: srv-cert + mountPath: "/srv-cert" + readOnly: true + {{- end }} + {{- if .Values.catalog.clientCASecret }} + - name: profile-collector-cert + mountPath: "/profile-collector-cert" + readOnly: true + {{- end }} command: - /bin/catalog args: @@ -37,29 +63,30 @@ spec: - -writeStatusName - {{ .Values.writeStatusNameCatalog }} {{- end }} - {{- if .Values.olm.tlsCertPath }} - - -tls-cert - - {{ .Values.olm.tlsCertPath }} + {{- if .Values.catalog.tlsSecret }} + - --tls-cert + - /srv-cert/tls.crt + - --tls-key + - /srv-cert/tls.key {{- end }} - {{- if .Values.olm.tlsKeyPath }} - - -tls-key - - {{ .Values.olm.tlsKeyPath }} + {{- if .Values.catalog.clientCASecret }} + - --client-ca + - /profile-collector-cert/tls.crt {{- end }} image: {{ .Values.catalog.image.ref }} imagePullPolicy: {{ .Values.catalog.image.pullPolicy }} ports: - containerPort: {{ .Values.catalog.service.internalPort }} - - containerPort: 8081 - name: metrics - protocol: TCP livenessProbe: httpGet: path: /healthz port: {{ .Values.catalog.service.internalPort }} + scheme: {{ if and .Values.catalog.tlsKeyPath .Values.catalog.tlsCertPath }}HTTPS{{ else }}HTTP{{end}} readinessProbe: httpGet: path: /healthz port: {{ .Values.catalog.service.internalPort }} + scheme: {{ if and .Values.catalog.tlsKeyPath .Values.catalog.tlsCertPath }}HTTPS{{ else }}HTTP{{end}} terminationMessagePolicy: FallbackToLogsOnError {{- if .Values.catalog.resources }} resources: diff --git a/staging/operator-lifecycle-manager/deploy/chart/values.yaml b/staging/operator-lifecycle-manager/deploy/chart/values.yaml index f0b4b2d75d..4f7f684b9a 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/values.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/values.yaml @@ -14,6 +14,9 @@ olm: pullPolicy: Always service: internalPort: 8080 + externalPort: metrics + # tlsSecret: olm-operator-serving-cert + # clientCASecret: pprof-serving-cert nodeSelector: kubernetes.io/os: linux resources: @@ -29,6 +32,9 @@ catalog: pullPolicy: Always service: internalPort: 8080 + externalPort: metrics + # tlsSecret: catalog-operator-serving-cert + # clientCASecret: pprof-serving-cert nodeSelector: kubernetes.io/os: linux resources: diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go new file mode 100644 index 0000000000..4fcee4e457 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go @@ -0,0 +1,60 @@ +package filemonitor + +import ( + "crypto/x509" + "io/ioutil" + "sync" + + "github.com/fsnotify/fsnotify" + "github.com/sirupsen/logrus" +) + +type certPoolStore struct { + mutex sync.RWMutex + certpool *x509.CertPool + clientCAPath string +} + +func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { + pem, err := ioutil.ReadFile(clientCAPath) + if err != nil { + return nil, err + } + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(pem) + + return &certPoolStore{ + mutex: sync.RWMutex{}, + certpool: pool, + clientCAPath: clientCAPath, + }, nil +} + +func (c *certPoolStore) storeCABundle(clientCAPath string) error { + pem, err := ioutil.ReadFile(clientCAPath) + if err == nil { + c.mutex.Lock() + defer c.mutex.Unlock() + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(pem) + c.certpool = pool + } + return err +} + +func (c *certPoolStore) HandleCABundleUpdate(logger logrus.FieldLogger, event fsnotify.Event) { + switch op := event.Op; op { + case fsnotify.Create: + logger.Debugf("got fs event for %v", event.Name) + + if err := c.storeCABundle(c.clientCAPath); err != nil { + logger.Debugf("unable to reload ca bundle: %v", err) + } else { + logger.Debugf("successfully reload ca bundle: %v", err) + } + } +} + +func (c *certPoolStore) GetCertPool() *x509.CertPool { + return c.certpool +} diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go index d7bb005ac2..9cf59c888c 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go @@ -1,43 +1,38 @@ package filemonitor import ( - "context" "crypto/tls" "crypto/x509" - "fmt" - "path/filepath" "sync" "github.com/fsnotify/fsnotify" "github.com/sirupsen/logrus" ) -type keystore struct { +type certStore struct { mutex sync.RWMutex cert *tls.Certificate tlsCrtPath string tlsKeyPath string } -type getCertFn = func(*tls.ClientHelloInfo) (*tls.Certificate, error) - -// NewKeystore returns a store for storing the certificate data and the ability to retrieve it safely -func NewKeystore(tlsCrt, tlsKey string) *keystore { +// NewCertStore returns a store for storing the certificate data and the ability to retrieve it safely +func NewCertStore(tlsCrt, tlsKey string) (*certStore, error) { cert, err := tls.LoadX509KeyPair(tlsCrt, tlsKey) if err != nil { - panic(err) + return nil, err } - return &keystore{ + return &certStore{ mutex: sync.RWMutex{}, cert: &cert, tlsCrtPath: tlsCrt, tlsKeyPath: tlsKey, - } + }, nil } // HandleFilesystemUpdate is intended to be used as the OnUpdateFn for a watcher // and expects the certificate files to be in the same directory. -func (k *keystore) HandleFilesystemUpdate(logger *logrus.Logger, event fsnotify.Event) { +func (k *certStore) HandleFilesystemUpdate(logger logrus.FieldLogger, event fsnotify.Event) { switch op := event.Op; op { case fsnotify.Create: logger.Debugf("got fs event for %v", event.Name) @@ -57,7 +52,7 @@ func (k *keystore) HandleFilesystemUpdate(logger *logrus.Logger, event fsnotify. } } -func (k *keystore) storeCertificate(tlsCrt, tlsKey string) error { +func (k *certStore) storeCertificate(tlsCrt, tlsKey string) error { cert, err := tls.LoadX509KeyPair(tlsCrt, tlsKey) if err == nil { k.mutex.Lock() @@ -67,24 +62,8 @@ func (k *keystore) storeCertificate(tlsCrt, tlsKey string) error { return err } -func (k *keystore) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { +func (k *certStore) GetCertificate() *tls.Certificate { k.mutex.RLock() defer k.mutex.RUnlock() - return k.cert, nil -} - -// OLMGetCertRotationFn is a convenience function for OLM use only, but serves as an example for monitoring file system events -func OLMGetCertRotationFn(logger *logrus.Logger, tlsCertPath, tlsKeyPath string) (getCertFn, error) { - if filepath.Dir(tlsCertPath) != filepath.Dir(tlsKeyPath) { - return nil, fmt.Errorf("certificates expected to be in same directory %v vs %v", tlsCertPath, tlsKeyPath) - } - - keystore := NewKeystore(tlsCertPath, tlsKeyPath) - watcher, err := NewWatch(logger, []string{filepath.Dir(tlsCertPath)}, keystore.HandleFilesystemUpdate) - if err != nil { - return nil, err - } - watcher.Run(context.Background()) - - return keystore.GetCertificate, nil + return k.cert } diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go index 92cbb7af54..022b22fc30 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go @@ -1,6 +1,7 @@ package filemonitor import ( + "context" "crypto/tls" "crypto/x509" "fmt" @@ -55,8 +56,18 @@ func TestOLMGetCertRotationFn(t *testing.T) { err = os.Symlink(filepath.Join("..", oldKey), loadKey) require.NoError(t, err) - tlsGetCertFn, err := OLMGetCertRotationFn(logger, loadCrt, loadKey) + certStore, err := NewCertStore(loadCrt, loadKey) + if err != nil { + require.NoError(t, err) + } + + tlsGetCertFn := func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + return certStore.GetCertificate(), nil + } + + csw, err := NewWatch(logger, []string{filepath.Dir(loadCrt), filepath.Dir(loadKey)}, certStore.HandleFilesystemUpdate) require.NoError(t, err) + csw.Run(context.Background()) // find a free port to listen on and start server listener, err := net.Listen("tcp", "localhost:0") @@ -113,7 +124,8 @@ func TestOLMGetCertRotationFn(t *testing.T) { // sometimes the the filesystem operations need time to catch up so the server cert is updated err = wait.PollImmediate(500*time.Millisecond, 10*time.Second, func() (bool, error) { - currentCert, _ := tlsGetCertFn(nil) + currentCert, err := tlsGetCertFn(nil) + require.NoError(t, err) info, err := x509.ParseCertificate(currentCert.Certificate[0]) if err != nil { return false, err diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go index c3b04e9fc3..bfb42ffb06 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go @@ -10,12 +10,12 @@ import ( type watcher struct { notify *fsnotify.Watcher pathsToWatch []string - logger *logrus.Logger - onUpdateFn func(*logrus.Logger, fsnotify.Event) + logger logrus.FieldLogger + onUpdateFn func(logrus.FieldLogger, fsnotify.Event) } // NewWatch sets up monitoring on a slice of paths and will execute the update function to process each event -func NewWatch(logger *logrus.Logger, pathsToWatch []string, onUpdateFn func(*logrus.Logger, fsnotify.Event)) (*watcher, error) { +func NewWatch(logger logrus.FieldLogger, pathsToWatch []string, onUpdateFn func(logrus.FieldLogger, fsnotify.Event)) (*watcher, error) { notify, err := fsnotify.NewWatcher() if err != nil { return nil, err diff --git a/staging/operator-lifecycle-manager/pkg/lib/profile/profile.go b/staging/operator-lifecycle-manager/pkg/lib/profile/profile.go index 76c516cbf4..46cf07edb4 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/profile/profile.go +++ b/staging/operator-lifecycle-manager/pkg/lib/profile/profile.go @@ -47,18 +47,28 @@ func RegisterHandlers(mux *http.ServeMux, options ...Option) { config.apply(options) if config.pprof { - mux.HandleFunc("/debug/pprof/", pprof.Index) + mux.Handle("/debug/pprof/", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Index))) } if config.cmdline { - mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.Handle("/debug/pprof/cmdline", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Cmdline))) } if config.profile { - mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.Handle("/debug/pprof/profile", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Profile))) } if config.symbol { - mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.Handle("/debug/pprof/symbol", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Symbol))) } if config.trace { - mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + mux.Handle("/debug/pprof/trace", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Trace))) } } + +func requireVerifiedClientCertificate(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil || len(r.TLS.VerifiedChains) == 0 { + w.WriteHeader(http.StatusForbidden) + return + } + h.ServeHTTP(w, r) + }) +} diff --git a/staging/operator-lifecycle-manager/pkg/lib/server/server.go b/staging/operator-lifecycle-manager/pkg/lib/server/server.go new file mode 100644 index 0000000000..c7307fc7b4 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/lib/server/server.go @@ -0,0 +1,77 @@ +package server + +import ( + "context" + "crypto/tls" + "fmt" + "net/http" + "path/filepath" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" +) + +func GetListenAndServeFunc(logger *logrus.Logger, tlsCertPath, tlsKeyPath, clientCAPath *string) (func() error, error) { + mux := http.NewServeMux() + profile.RegisterHandlers(mux) + mux.Handle("/metrics", promhttp.Handler()) + mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + s := http.Server{ + Handler: mux, + Addr: ":8080", + } + listenAndServe := s.ListenAndServe + + if *tlsCertPath != "" && *tlsKeyPath != "" { + logger.Info("TLS keys set, using https for metrics") + + certStore, err := filemonitor.NewCertStore(*tlsCertPath, *tlsKeyPath) + if err != nil { + return nil, fmt.Errorf("Certificate monitoring for metrics (https) failed: %v", err) + } + + csw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*tlsCertPath), filepath.Dir(*tlsKeyPath)}, certStore.HandleFilesystemUpdate) + if err != nil { + return nil, fmt.Errorf("error creating cert file watcher: %v", err) + } + csw.Run(context.Background()) + certPoolStore, err := filemonitor.NewCertPoolStore(*clientCAPath) + cpsw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*clientCAPath)}, certPoolStore.HandleCABundleUpdate) + if err != nil { + return nil, fmt.Errorf("error creating cert file watcher: %v", err) + } + cpsw.Run(context.Background()) + + s.Addr = ":8443" + s.TLSConfig = &tls.Config{ + GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + return certStore.GetCertificate(), nil + }, + GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) { + var certs []tls.Certificate + if cert := certStore.GetCertificate(); cert != nil { + certs = append(certs, *cert) + } + return &tls.Config{ + Certificates: certs, + ClientCAs: certPoolStore.GetCertPool(), + ClientAuth: tls.VerifyClientCertIfGiven, + }, nil + }, + } + + listenAndServe = func() error { + return s.ListenAndServeTLS("", "") + } + } else if *tlsCertPath != "" || *tlsKeyPath != "" { + return nil, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled") + } else { + logger.Info("TLS keys not set, using non-https for metrics") + } + return listenAndServe, nil +} diff --git a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index 698e9309b1..9cb87e23d9 100644 --- a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -89,7 +89,7 @@ var _ = Describe("Install Plan", func() { BeforeEach(func() { counter = 0 - for _, metric := range getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8081") { + for _, metric := range getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8080") { if metric.Family == "installplan_warnings_total" { counter = metric.Value } @@ -189,7 +189,7 @@ var _ = Describe("Install Plan", func() { It("increments a metric counting the warning", func() { Eventually(func() []Metric { - return getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8081") + return getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8080") }).Should(ContainElement(LikeMetric( WithFamily("installplan_warnings_total"), WithValueGreaterThan(counter), diff --git a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go index e733d637f7..b0aa628035 100644 --- a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go @@ -80,7 +80,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("generates csv_abnormal metric for OLM pod", func() { - Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8081")).To(And( + Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8080")).To(And( ContainElement(LikeMetric( WithFamily("csv_abnormal"), WithName(failingCSV.Name), @@ -108,7 +108,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes its associated CSV metrics", func() { // Verify that when the csv has been deleted, it deletes the corresponding CSV metrics - Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8081")).ToNot(And( + Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8080")).ToNot(And( ContainElement(LikeMetric(WithFamily("csv_abnormal"), WithName(failingCSV.Name))), ContainElement(LikeMetric(WithFamily("csv_succeeded"), WithName(failingCSV.Name))), )) @@ -138,7 +138,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { // Verify metrics have been emitted for subscription Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), WithName("metric-subscription-for-create"), @@ -153,7 +153,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { // Verify metrics have been emitted for dependency resolution Eventually(func() bool { return Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(ContainElement(LikeMetric( WithFamily("olm_resolution_duration_seconds"), WithLabel("outcome", "failed"), @@ -168,7 +168,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-update", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-update")))) Eventually(func() error { s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{}) @@ -189,7 +189,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the old Subscription metric and emits the new metric", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(And( Not(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), @@ -223,7 +223,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the old subscription metric and emits the new metric(there is only one metric for the subscription)", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(And( Not(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), @@ -253,7 +253,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-delete", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-delete")))) if subscriptionCleanup != nil { subscriptionCleanup() @@ -269,7 +269,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the Subscription metric", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).ShouldNot(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithName("metric-subscription-for-delete")))) }) }) @@ -312,7 +312,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("emits metrics for the catalogSource", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(And( ContainElement(LikeMetric( WithFamily("catalog_source_count"), @@ -332,7 +332,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("deletes the metrics for the CatalogSource", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(And( Not(ContainElement(LikeMetric( WithFamily("catalogsource_ready"), @@ -356,7 +356,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("emits metrics for the CatlogSource with a Value greater than 0", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }).Should(And( ContainElement(LikeMetric( WithFamily("catalogsource_ready"), @@ -366,7 +366,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { )), )) Consistently(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8081") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") }, "3m").Should(And( ContainElement(LikeMetric( WithFamily("catalogsource_ready"), diff --git a/values.yaml b/values.yaml index aa68e15ded..d4e7826537 100644 --- a/values.yaml +++ b/values.yaml @@ -13,7 +13,9 @@ olm: ref: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 pullPolicy: IfNotPresent service: - internalPort: 8080 + internalPort: 8443 + externalPort: 8443 + clientCASecret: olm-operator-serving-cert nodeSelector: kubernetes.io/os: linux node-role.kubernetes.io/master: "" @@ -29,8 +31,7 @@ olm: operator: Exists effect: NoExecute tolerationSeconds: 120 - tlsCertPath: /var/run/secrets/serving-cert/tls.crt - tlsKeyPath: /var/run/secrets/serving-cert/tls.key + tlsSecret: olm-operator-serving-cert resources: requests: cpu: 10m @@ -41,7 +42,12 @@ catalog: ref: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 pullPolicy: IfNotPresent service: - internalPort: 8080 + internalPort: 8443 + externalPort: 8443 + clientCASecret: catalog-operator-serving-cert + tlsKeyPath: foo + tlsCertPath: bar + tlsSecret: catalog-operator-serving-cert nodeSelector: kubernetes.io/os: linux node-role.kubernetes.io/master: "" diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go index 4f945eb008..805334efbb 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "crypto/tls" "flag" "fmt" "net/http" @@ -10,7 +9,6 @@ import ( "time" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" utilclock "k8s.io/apimachinery/pkg/util/clock" k8sscheme "k8s.io/client-go/kubernetes/scheme" @@ -18,10 +16,9 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals" "github.com/operator-framework/operator-lifecycle-manager/pkg/metrics" olmversion "github.com/operator-framework/operator-lifecycle-manager/pkg/version" @@ -67,8 +64,9 @@ var ( tlsCertPath = flag.String( "tls-cert", "", "Path to use for certificate key (requires tls-key)") - profiling = flag.Bool( - "profiling", false, "serve profiling data (on port 8080)") + profiling = flag.Bool("profiling", false, "deprecated") + + clientCAPath = flag.String("client-ca", "", "path to watch for client ca bundle") installPlanTimeout = flag.Duration("install-plan-retry-timeout", 1*time.Minute, "time since first attempt at which plan execution errors are considered fatal") bundleUnpackTimeout = flag.Duration("bundle-unpack-timeout", 10*time.Minute, "The time limit for bundle unpacking, after which InstallPlan execution is considered to have failed. 0 is considered as having no timeout.") @@ -106,59 +104,16 @@ func main() { *catalogNamespace = catalogNamespaceEnvVarValue } - var useTLS bool - if *tlsCertPath != "" && *tlsKeyPath == "" || *tlsCertPath == "" && *tlsKeyPath != "" { - logger.Warn("both --tls-key and --tls-crt must be provided for TLS to be enabled, falling back to non-https") - } else if *tlsCertPath == "" && *tlsKeyPath == "" { - logger.Info("TLS keys not set, using non-https for metrics") - } else { - logger.Info("TLS keys set, using https for metrics") - useTLS = true - } - - // Serve a health check. - healthMux := http.NewServeMux() - healthMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - // Serve profiling if enabled - if *profiling { - logger.Infof("profiling enabled") - profile.RegisterHandlers(healthMux) + listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath) + if err != nil { + logger.Fatal("Error setting up health/metric/pprof service: %v", err) } - go http.ListenAndServe(":8080", healthMux) - - metricsMux := http.NewServeMux() - metricsMux.Handle("/metrics", promhttp.Handler()) - if useTLS { - tlsGetCertFn, err := filemonitor.OLMGetCertRotationFn(logger, *tlsCertPath, *tlsKeyPath) - if err != nil { - logger.Errorf("Certificate monitoring for metrics (https) failed: %v", err) + go func() { + if err := listenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Error(err) } - - go func() { - httpsServer := &http.Server{ - Addr: ":8081", - Handler: metricsMux, - TLSConfig: &tls.Config{ - GetCertificate: tlsGetCertFn, - }, - } - err := httpsServer.ListenAndServeTLS("", "") - if err != nil { - logger.Errorf("Metrics (https) serving failed: %v", err) - } - }() - } else { - go func() { - err := http.ListenAndServe(":8081", metricsMux) - if err != nil { - logger.Errorf("Metrics (http) serving failed: %v", err) - } - }() - } + }() // create a config client for operator status config, err := clientcmd.BuildConfigFromFlags("", *kubeConfigPath) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go index 087ebb74a8..f9bec9f689 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "crypto/tls" "flag" "fmt" "net/http" @@ -12,7 +11,6 @@ import ( configclientset "github.com/openshift/client-go/config/clientset/versioned" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" "github.com/spf13/pflag" v1 "k8s.io/api/core/v1" @@ -23,11 +21,10 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift" "github.com/operator-framework/operator-lifecycle-manager/pkg/feature" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals" "github.com/operator-framework/operator-lifecycle-manager/pkg/metrics" olmversion "github.com/operator-framework/operator-lifecycle-manager/pkg/version" @@ -66,8 +63,9 @@ var ( tlsCertPath = pflag.String( "tls-cert", "", "Path to use for certificate key (requires tls-key)") - profiling = pflag.Bool( - "profiling", false, "serve profiling data (on port 8080)") + profiling = pflag.Bool("profiling", false, "deprecated") + + clientCAPath = pflag.String("client-ca", "", "path to watch for client ca bundle") namespace = pflag.String( "namespace", "", "namespace where cleanup runs") @@ -120,65 +118,17 @@ func main() { } logger.Infof("log level %s", logger.Level) - var useTLS bool - if *tlsCertPath != "" && *tlsKeyPath == "" || *tlsCertPath == "" && *tlsKeyPath != "" { - logger.Warn("both --tls-key and --tls-crt must be provided for TLS to be enabled, falling back to non-https") - } else if *tlsCertPath == "" && *tlsKeyPath == "" { - logger.Info("TLS keys not set, using non-https for metrics") - } else { - logger.Info("TLS keys set, using https for metrics") - useTLS = true - } - - // Serve a health check. - healthMux := http.NewServeMux() - healthMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }) - - // Serve profiling if enabled - if *profiling { - logger.Infof("profiling enabled") - profile.RegisterHandlers(healthMux) + listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath) + if err != nil { + logger.Fatal("Error setting up health/metric/pprof service: %v", err) } go func() { - err := http.ListenAndServe(":8080", healthMux) - if err != nil { - logger.Errorf("Health serving failed: %v", err) + if err := listenAndServe(); err != nil && err != http.ErrServerClosed { + logger.Error(err) } }() - metricsMux := http.NewServeMux() - metricsMux.Handle("/metrics", promhttp.Handler()) - if useTLS { - tlsGetCertFn, err := filemonitor.OLMGetCertRotationFn(logger, *tlsCertPath, *tlsKeyPath) - if err != nil { - logger.Errorf("Certificate monitoring for metrics (https) failed: %v", err) - } - - go func() { - httpsServer := &http.Server{ - Addr: ":8081", - Handler: metricsMux, - TLSConfig: &tls.Config{ - GetCertificate: tlsGetCertFn, - }, - } - err := httpsServer.ListenAndServeTLS("", "") - if err != nil { - logger.Errorf("Metrics (https) serving failed: %v", err) - } - }() - } else { - go func() { - err := http.ListenAndServe(":8081", metricsMux) - if err != nil { - logger.Errorf("Metrics (http) serving failed: %v", err) - } - }() - } - mgr, err := Manager(ctx, *debug) if err != nil { logger.WithError(err).Fatalf("error configuring controller manager") diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go new file mode 100644 index 0000000000..4fcee4e457 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go @@ -0,0 +1,60 @@ +package filemonitor + +import ( + "crypto/x509" + "io/ioutil" + "sync" + + "github.com/fsnotify/fsnotify" + "github.com/sirupsen/logrus" +) + +type certPoolStore struct { + mutex sync.RWMutex + certpool *x509.CertPool + clientCAPath string +} + +func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { + pem, err := ioutil.ReadFile(clientCAPath) + if err != nil { + return nil, err + } + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(pem) + + return &certPoolStore{ + mutex: sync.RWMutex{}, + certpool: pool, + clientCAPath: clientCAPath, + }, nil +} + +func (c *certPoolStore) storeCABundle(clientCAPath string) error { + pem, err := ioutil.ReadFile(clientCAPath) + if err == nil { + c.mutex.Lock() + defer c.mutex.Unlock() + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(pem) + c.certpool = pool + } + return err +} + +func (c *certPoolStore) HandleCABundleUpdate(logger logrus.FieldLogger, event fsnotify.Event) { + switch op := event.Op; op { + case fsnotify.Create: + logger.Debugf("got fs event for %v", event.Name) + + if err := c.storeCABundle(c.clientCAPath); err != nil { + logger.Debugf("unable to reload ca bundle: %v", err) + } else { + logger.Debugf("successfully reload ca bundle: %v", err) + } + } +} + +func (c *certPoolStore) GetCertPool() *x509.CertPool { + return c.certpool +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go index d7bb005ac2..9cf59c888c 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater.go @@ -1,43 +1,38 @@ package filemonitor import ( - "context" "crypto/tls" "crypto/x509" - "fmt" - "path/filepath" "sync" "github.com/fsnotify/fsnotify" "github.com/sirupsen/logrus" ) -type keystore struct { +type certStore struct { mutex sync.RWMutex cert *tls.Certificate tlsCrtPath string tlsKeyPath string } -type getCertFn = func(*tls.ClientHelloInfo) (*tls.Certificate, error) - -// NewKeystore returns a store for storing the certificate data and the ability to retrieve it safely -func NewKeystore(tlsCrt, tlsKey string) *keystore { +// NewCertStore returns a store for storing the certificate data and the ability to retrieve it safely +func NewCertStore(tlsCrt, tlsKey string) (*certStore, error) { cert, err := tls.LoadX509KeyPair(tlsCrt, tlsKey) if err != nil { - panic(err) + return nil, err } - return &keystore{ + return &certStore{ mutex: sync.RWMutex{}, cert: &cert, tlsCrtPath: tlsCrt, tlsKeyPath: tlsKey, - } + }, nil } // HandleFilesystemUpdate is intended to be used as the OnUpdateFn for a watcher // and expects the certificate files to be in the same directory. -func (k *keystore) HandleFilesystemUpdate(logger *logrus.Logger, event fsnotify.Event) { +func (k *certStore) HandleFilesystemUpdate(logger logrus.FieldLogger, event fsnotify.Event) { switch op := event.Op; op { case fsnotify.Create: logger.Debugf("got fs event for %v", event.Name) @@ -57,7 +52,7 @@ func (k *keystore) HandleFilesystemUpdate(logger *logrus.Logger, event fsnotify. } } -func (k *keystore) storeCertificate(tlsCrt, tlsKey string) error { +func (k *certStore) storeCertificate(tlsCrt, tlsKey string) error { cert, err := tls.LoadX509KeyPair(tlsCrt, tlsKey) if err == nil { k.mutex.Lock() @@ -67,24 +62,8 @@ func (k *keystore) storeCertificate(tlsCrt, tlsKey string) error { return err } -func (k *keystore) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { +func (k *certStore) GetCertificate() *tls.Certificate { k.mutex.RLock() defer k.mutex.RUnlock() - return k.cert, nil -} - -// OLMGetCertRotationFn is a convenience function for OLM use only, but serves as an example for monitoring file system events -func OLMGetCertRotationFn(logger *logrus.Logger, tlsCertPath, tlsKeyPath string) (getCertFn, error) { - if filepath.Dir(tlsCertPath) != filepath.Dir(tlsKeyPath) { - return nil, fmt.Errorf("certificates expected to be in same directory %v vs %v", tlsCertPath, tlsKeyPath) - } - - keystore := NewKeystore(tlsCertPath, tlsKeyPath) - watcher, err := NewWatch(logger, []string{filepath.Dir(tlsCertPath)}, keystore.HandleFilesystemUpdate) - if err != nil { - return nil, err - } - watcher.Run(context.Background()) - - return keystore.GetCertificate, nil + return k.cert } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go index c3b04e9fc3..bfb42ffb06 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/watcher.go @@ -10,12 +10,12 @@ import ( type watcher struct { notify *fsnotify.Watcher pathsToWatch []string - logger *logrus.Logger - onUpdateFn func(*logrus.Logger, fsnotify.Event) + logger logrus.FieldLogger + onUpdateFn func(logrus.FieldLogger, fsnotify.Event) } // NewWatch sets up monitoring on a slice of paths and will execute the update function to process each event -func NewWatch(logger *logrus.Logger, pathsToWatch []string, onUpdateFn func(*logrus.Logger, fsnotify.Event)) (*watcher, error) { +func NewWatch(logger logrus.FieldLogger, pathsToWatch []string, onUpdateFn func(logrus.FieldLogger, fsnotify.Event)) (*watcher, error) { notify, err := fsnotify.NewWatcher() if err != nil { return nil, err diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile/profile.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile/profile.go index 76c516cbf4..46cf07edb4 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile/profile.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile/profile.go @@ -47,18 +47,28 @@ func RegisterHandlers(mux *http.ServeMux, options ...Option) { config.apply(options) if config.pprof { - mux.HandleFunc("/debug/pprof/", pprof.Index) + mux.Handle("/debug/pprof/", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Index))) } if config.cmdline { - mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.Handle("/debug/pprof/cmdline", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Cmdline))) } if config.profile { - mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.Handle("/debug/pprof/profile", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Profile))) } if config.symbol { - mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.Handle("/debug/pprof/symbol", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Symbol))) } if config.trace { - mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + mux.Handle("/debug/pprof/trace", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Trace))) } } + +func requireVerifiedClientCertificate(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil || len(r.TLS.VerifiedChains) == 0 { + w.WriteHeader(http.StatusForbidden) + return + } + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server/server.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server/server.go new file mode 100644 index 0000000000..c7307fc7b4 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server/server.go @@ -0,0 +1,77 @@ +package server + +import ( + "context" + "crypto/tls" + "fmt" + "net/http" + "path/filepath" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" +) + +func GetListenAndServeFunc(logger *logrus.Logger, tlsCertPath, tlsKeyPath, clientCAPath *string) (func() error, error) { + mux := http.NewServeMux() + profile.RegisterHandlers(mux) + mux.Handle("/metrics", promhttp.Handler()) + mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + + s := http.Server{ + Handler: mux, + Addr: ":8080", + } + listenAndServe := s.ListenAndServe + + if *tlsCertPath != "" && *tlsKeyPath != "" { + logger.Info("TLS keys set, using https for metrics") + + certStore, err := filemonitor.NewCertStore(*tlsCertPath, *tlsKeyPath) + if err != nil { + return nil, fmt.Errorf("Certificate monitoring for metrics (https) failed: %v", err) + } + + csw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*tlsCertPath), filepath.Dir(*tlsKeyPath)}, certStore.HandleFilesystemUpdate) + if err != nil { + return nil, fmt.Errorf("error creating cert file watcher: %v", err) + } + csw.Run(context.Background()) + certPoolStore, err := filemonitor.NewCertPoolStore(*clientCAPath) + cpsw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*clientCAPath)}, certPoolStore.HandleCABundleUpdate) + if err != nil { + return nil, fmt.Errorf("error creating cert file watcher: %v", err) + } + cpsw.Run(context.Background()) + + s.Addr = ":8443" + s.TLSConfig = &tls.Config{ + GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { + return certStore.GetCertificate(), nil + }, + GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) { + var certs []tls.Certificate + if cert := certStore.GetCertificate(); cert != nil { + certs = append(certs, *cert) + } + return &tls.Config{ + Certificates: certs, + ClientCAs: certPoolStore.GetCertPool(), + ClientAuth: tls.VerifyClientCertIfGiven, + }, nil + }, + } + + listenAndServe = func() error { + return s.ListenAndServeTLS("", "") + } + } else if *tlsCertPath != "" || *tlsKeyPath != "" { + return nil, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled") + } else { + logger.Info("TLS keys not set, using non-https for metrics") + } + return listenAndServe, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 37f06ed339..3860cc9dd2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -556,6 +556,7 @@ github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile github.com/operator-framework/operator-lifecycle-manager/pkg/lib/proxy github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped +github.com/operator-framework/operator-lifecycle-manager/pkg/lib/server github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals github.com/operator-framework/operator-lifecycle-manager/pkg/lib/time github.com/operator-framework/operator-lifecycle-manager/pkg/metrics From 0d1d1f22a57501f0b3242a66b8fbde443324cca2 Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Wed, 14 Jul 2021 14:54:49 -0400 Subject: [PATCH 06/30] Remove unused trace log from LegacySyncHandler. This line creates an info-level logger, writes a trace-level log to it, and discards the logger reference. This looks like cruft and is responsible for some heap churn. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 8c8b18bacbc8033ef9d2a8847e730b3aa17247e6 --- .../pkg/lib/queueinformer/queueinformer.go | 2 -- .../pkg/lib/queueinformer/queueinformer.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go b/staging/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go index cef9db6719..02a66cb527 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go +++ b/staging/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go @@ -2,7 +2,6 @@ package queueinformer import ( "context" - "fmt" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -170,7 +169,6 @@ func (l LegacySyncHandler) ToSyncer() kubestate.Syncer { // ToSyncerWithDelete returns the Syncer equivalent of the given sync handler and delete function. func (l LegacySyncHandler) ToSyncerWithDelete(onDelete func(obj interface{})) kubestate.Syncer { var syncer kubestate.SyncFunc = func(ctx context.Context, event kubestate.ResourceEvent) error { - logrus.New().WithField("event", fmt.Sprintf("%+v", event)).Trace("legacy syncer received event") switch event.Type() { case kubestate.ResourceDeleted: if onDelete != nil { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go index cef9db6719..02a66cb527 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/queueinformer.go @@ -2,7 +2,6 @@ package queueinformer import ( "context" - "fmt" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -170,7 +169,6 @@ func (l LegacySyncHandler) ToSyncer() kubestate.Syncer { // ToSyncerWithDelete returns the Syncer equivalent of the given sync handler and delete function. func (l LegacySyncHandler) ToSyncerWithDelete(onDelete func(obj interface{})) kubestate.Syncer { var syncer kubestate.SyncFunc = func(ctx context.Context, event kubestate.ResourceEvent) error { - logrus.New().WithField("event", fmt.Sprintf("%+v", event)).Trace("legacy syncer received event") switch event.Type() { case kubestate.ResourceDeleted: if onDelete != nil { From cb9cb9fc70d6e1e753ed73fd966762501c77887e Mon Sep 17 00:00:00 2001 From: Zvi Cahana Date: Tue, 13 Jul 2021 16:24:16 +0300 Subject: [PATCH 07/30] Add a catalog-operator flag to set opmImage Signed-off-by: Zvi Cahana Upstream-repository: operator-lifecycle-manager Upstream-commit: 04b665cea41b2ee63bf89b5ca01712f1214f2a52 --- staging/operator-lifecycle-manager/cmd/catalog/main.go | 8 ++++++-- .../pkg/controller/operators/catalog/operator.go | 4 ++-- .../operator-lifecycle-manager/cmd/catalog/main.go | 8 ++++++-- .../pkg/controller/operators/catalog/operator.go | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/staging/operator-lifecycle-manager/cmd/catalog/main.go b/staging/operator-lifecycle-manager/cmd/catalog/main.go index 805334efbb..f8128a4c2c 100644 --- a/staging/operator-lifecycle-manager/cmd/catalog/main.go +++ b/staging/operator-lifecycle-manager/cmd/catalog/main.go @@ -28,7 +28,8 @@ const ( catalogNamespaceEnvVarName = "GLOBAL_CATALOG_NAMESPACE" defaultWakeupInterval = 15 * time.Minute defaultCatalogNamespace = "openshift-operator-lifecycle-manager" - defaultConfigMapServerImage = "quay.io/operatorframework/configmap-operator-registry:latest" + defaultConfigMapServerImage = "quay.io/operator-framework/configmap-operator-registry:latest" + defaultOPMImage = "quay.io/operator-framework/upstream-opm-builder:latest" defaultUtilImage = "quay.io/operator-framework/olm:latest" defaultOperatorName = "" ) @@ -47,6 +48,9 @@ var ( configmapServerImage = flag.String( "configmapServerImage", defaultConfigMapServerImage, "the image to use for serving the operator registry api for a configmap") + opmImage = flag.String( + "opmImage", defaultOPMImage, "the image to use for unpacking bundle content with opm") + utilImage = flag.String( "util-image", defaultUtilImage, "an image containing custom olm utilities") @@ -131,7 +135,7 @@ func main() { } // Create a new instance of the operator. - op, err := catalog.NewOperator(ctx, *kubeConfigPath, utilclock.RealClock{}, logger, *wakeupInterval, *configmapServerImage, *utilImage, *catalogNamespace, k8sscheme.Scheme, *installPlanTimeout, *bundleUnpackTimeout) + op, err := catalog.NewOperator(ctx, *kubeConfigPath, utilclock.RealClock{}, logger, *wakeupInterval, *configmapServerImage, *opmImage, *utilImage, *catalogNamespace, k8sscheme.Scheme, *installPlanTimeout, *bundleUnpackTimeout) if err != nil { log.Panicf("error configuring operator: %s", err.Error()) } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index efd1685b90..6aec1d1ffe 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -115,7 +115,7 @@ type Operator struct { type CatalogSourceSyncFunc func(logger *logrus.Entry, in *v1alpha1.CatalogSource) (out *v1alpha1.CatalogSource, continueSync bool, syncError error) // NewOperator creates a new Catalog Operator. -func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration) (*Operator, error) { +func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, opmImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration) (*Operator, error) { resyncPeriod := queueinformer.ResyncWithJitter(resync, 0.2) config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath) if err != nil { @@ -351,7 +351,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo bundle.WithPodLister(podInformer.Lister()), bundle.WithRoleLister(roleInformer.Lister()), bundle.WithRoleBindingLister(roleBindingInformer.Lister()), - bundle.WithOPMImage(configmapRegistryImage), + bundle.WithOPMImage(opmImage), bundle.WithUtilImage(utilImage), bundle.WithNow(op.now), bundle.WithUnpackTimeout(op.bundleUnpackTimeout), diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go index 805334efbb..f8128a4c2c 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/catalog/main.go @@ -28,7 +28,8 @@ const ( catalogNamespaceEnvVarName = "GLOBAL_CATALOG_NAMESPACE" defaultWakeupInterval = 15 * time.Minute defaultCatalogNamespace = "openshift-operator-lifecycle-manager" - defaultConfigMapServerImage = "quay.io/operatorframework/configmap-operator-registry:latest" + defaultConfigMapServerImage = "quay.io/operator-framework/configmap-operator-registry:latest" + defaultOPMImage = "quay.io/operator-framework/upstream-opm-builder:latest" defaultUtilImage = "quay.io/operator-framework/olm:latest" defaultOperatorName = "" ) @@ -47,6 +48,9 @@ var ( configmapServerImage = flag.String( "configmapServerImage", defaultConfigMapServerImage, "the image to use for serving the operator registry api for a configmap") + opmImage = flag.String( + "opmImage", defaultOPMImage, "the image to use for unpacking bundle content with opm") + utilImage = flag.String( "util-image", defaultUtilImage, "an image containing custom olm utilities") @@ -131,7 +135,7 @@ func main() { } // Create a new instance of the operator. - op, err := catalog.NewOperator(ctx, *kubeConfigPath, utilclock.RealClock{}, logger, *wakeupInterval, *configmapServerImage, *utilImage, *catalogNamespace, k8sscheme.Scheme, *installPlanTimeout, *bundleUnpackTimeout) + op, err := catalog.NewOperator(ctx, *kubeConfigPath, utilclock.RealClock{}, logger, *wakeupInterval, *configmapServerImage, *opmImage, *utilImage, *catalogNamespace, k8sscheme.Scheme, *installPlanTimeout, *bundleUnpackTimeout) if err != nil { log.Panicf("error configuring operator: %s", err.Error()) } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index efd1685b90..6aec1d1ffe 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -115,7 +115,7 @@ type Operator struct { type CatalogSourceSyncFunc func(logger *logrus.Entry, in *v1alpha1.CatalogSource) (out *v1alpha1.CatalogSource, continueSync bool, syncError error) // NewOperator creates a new Catalog Operator. -func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration) (*Operator, error) { +func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clock, logger *logrus.Logger, resync time.Duration, configmapRegistryImage, opmImage, utilImage string, operatorNamespace string, scheme *runtime.Scheme, installPlanTimeout time.Duration, bundleUnpackTimeout time.Duration) (*Operator, error) { resyncPeriod := queueinformer.ResyncWithJitter(resync, 0.2) config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath) if err != nil { @@ -351,7 +351,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo bundle.WithPodLister(podInformer.Lister()), bundle.WithRoleLister(roleInformer.Lister()), bundle.WithRoleBindingLister(roleBindingInformer.Lister()), - bundle.WithOPMImage(configmapRegistryImage), + bundle.WithOPMImage(opmImage), bundle.WithUtilImage(utilImage), bundle.WithNow(op.now), bundle.WithUnpackTimeout(op.bundleUnpackTimeout), From 83eb1ce1494bc9ad57b25e5eaab73f555924202a Mon Sep 17 00:00:00 2001 From: Zvi Cahana Date: Wed, 7 Jul 2021 18:18:56 +0300 Subject: [PATCH 08/30] Enable gzip compression when unpacking bundles to ConfigMap Signed-off-by: Zvi Cahana Upstream-repository: operator-lifecycle-manager Upstream-commit: fd344476b1d04b9439590c5fd0da81d7efc3b600 --- .../pkg/controller/bundle/bundle_unpacker.go | 11 ++++++++--- .../pkg/controller/bundle/bundle_unpacker_test.go | 12 ++++++------ .../pkg/controller/bundle/bundle_unpacker.go | 11 ++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 67e86de300..962e8066dd 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -100,9 +100,14 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string ImagePullSecrets: secrets, Containers: []corev1.Container{ { - Name: "extract", - Image: c.opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", cmRef.Namespace, "-c", cmRef.Name}, + Name: "extract", + Image: c.opmImage, + Command: []string{"opm", "alpha", "bundle", "extract", + "-m", "/bundle/", + "-n", cmRef.Namespace, + "-c", cmRef.Name, + "-z", + }, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, diff --git a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go index 0149606048..5d8ff740ab 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker_test.go @@ -222,7 +222,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, @@ -399,7 +399,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, @@ -616,7 +616,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, @@ -828,7 +828,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, @@ -1010,7 +1010,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, @@ -1203,7 +1203,7 @@ func TestConfigMapUnpacker(t *testing.T) { { Name: "extract", Image: opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash}, + Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", "ns-a", "-c", pathHash, "-z"}, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go index 67e86de300..962e8066dd 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/bundle/bundle_unpacker.go @@ -100,9 +100,14 @@ func (c *ConfigMapUnpacker) job(cmRef *corev1.ObjectReference, bundlePath string ImagePullSecrets: secrets, Containers: []corev1.Container{ { - Name: "extract", - Image: c.opmImage, - Command: []string{"opm", "alpha", "bundle", "extract", "-m", "/bundle/", "-n", cmRef.Namespace, "-c", cmRef.Name}, + Name: "extract", + Image: c.opmImage, + Command: []string{"opm", "alpha", "bundle", "extract", + "-m", "/bundle/", + "-n", cmRef.Namespace, + "-c", cmRef.Name, + "-z", + }, Env: []corev1.EnvVar{ { Name: configmap.EnvContainerImage, From 3626e03b29bddac5e174dbd9485a0e8a4da646b4 Mon Sep 17 00:00:00 2001 From: Zvi Cahana Date: Thu, 15 Jul 2021 14:58:07 +0300 Subject: [PATCH 09/30] Bump operator-registry to v1.17.5 Signed-off-by: Zvi Cahana Upstream-repository: operator-lifecycle-manager Upstream-commit: 93ece2a5618ee578c918bf6e5e0ad57d536ad85c --- go.mod | 2 +- staging/operator-lifecycle-manager/go.mod | 2 +- staging/operator-lifecycle-manager/go.sum | 105 +++++++++++++++------- vendor/modules.txt | 2 +- 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index e6ce900aa6..281469c1e4 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/openshift/api v0.0.0-20200331152225-585af27e34fd github.com/operator-framework/api v0.10.1 github.com/operator-framework/operator-lifecycle-manager v0.0.0-00010101000000-000000000000 - github.com/operator-framework/operator-registry v1.13.6 + github.com/operator-framework/operator-registry v1.17.5 github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 diff --git a/staging/operator-lifecycle-manager/go.mod b/staging/operator-lifecycle-manager/go.mod index 3bccaa8fd8..8a02b55ae5 100644 --- a/staging/operator-lifecycle-manager/go.mod +++ b/staging/operator-lifecycle-manager/go.mod @@ -25,7 +25,7 @@ require ( github.com/openshift/api v0.0.0-20200331152225-585af27e34fd github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 github.com/operator-framework/api v0.10.1 - github.com/operator-framework/operator-registry v1.13.6 + github.com/operator-framework/operator-registry v1.17.5 github.com/otiai10/copy v1.2.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 diff --git a/staging/operator-lifecycle-manager/go.sum b/staging/operator-lifecycle-manager/go.sum index 0f485b6228..6a43a12331 100644 --- a/staging/operator-lifecycle-manager/go.sum +++ b/staging/operator-lifecycle-manager/go.sum @@ -77,6 +77,7 @@ github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4 github.com/Masterminds/vcs v1.13.1 h1:NL3G1X7/7xduQtA2sJLpVpfHTNBALVNSjob6KEjPXNQ= github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= @@ -103,6 +104,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -111,7 +113,7 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -119,6 +121,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -294,6 +297,7 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -319,6 +323,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -336,12 +341,21 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-bindata/go-bindata/v3 v3.1.3 h1:F0nVttLC3ws0ojc7p60veTurcOm//D4QBODNM7EGrCI= github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= +github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= +github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -355,9 +369,10 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= @@ -533,7 +548,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= @@ -568,6 +582,10 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-health-probe v0.3.2/go.mod h1:izVOQ4RWbjUR6lm4nn+VLJyQ+FyaiGmprEYgI04Gs7U= +github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= +github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc= +github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8RYb1Y7fYivughjxojTmIu5iAIjSrSLCLeqE= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -601,8 +619,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -618,9 +635,12 @@ github.com/itchyny/gojq v0.11.0 h1:z7HnaKZ6erVzxPo3BkhJBG7jHmzKdAW8Hcse5N6YAic= github.com/itchyny/gojq v0.11.0/go.mod h1:my6D2qN2Sm6qa+/5GsPDUZlCWGR+U8Qsa9he76sudv0= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -628,6 +648,8 @@ github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/joelanford/ignore v0.0.0-20210607151042-0d25dc18b62d h1:A2/B900ip/Z20TzkLeGRNy1s6J2HmH9AmGt+dHyqb4I= +github.com/joelanford/ignore v0.0.0-20210607151042-0d25dc18b62d/go.mod h1:7HQupe4vyNxMKXmM5DFuwXHsqwMyglcYmZBtlDPIcZ8= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -649,6 +671,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= @@ -660,6 +683,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv 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= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -731,8 +756,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU= -github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0= github.com/mikefarah/yq/v3 v3.0.0-20201202084205-8846255d1c37 h1:lPmsut5Sk7eK2BmDXuvNEvMbT7MkAJBu64Yxr7iJ6nk= github.com/mikefarah/yq/v3 v3.0.0-20201202084205-8846255d1c37/go.mod h1:dYWq+UWoFCDY1TndvFUQuhBbIYmZpjreC8adEAx93zE= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -787,7 +810,6 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -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= @@ -806,9 +828,9 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -818,8 +840,8 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= @@ -851,11 +873,11 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q= +github.com/operator-framework/api v0.7.1/go.mod h1:L7IvLd/ckxJEJg/t4oTTlnHKAJIP/p51AvEslW3wYdY= github.com/operator-framework/api v0.10.1 h1:2tBjIr4hRZ0iaJ4UuenVjocbo9xrJi1O409K/tlEddo= github.com/operator-framework/api v0.10.1/go.mod h1:tV0BUNvly7szq28ZPBXhjp1Sqg5yHCOeX19ui9K4vjI= -github.com/operator-framework/operator-registry v1.13.6 h1:h/dIjQQS7uneQNRifrSz7h0xg4Xyjg6C9f6XZofbMPg= -github.com/operator-framework/operator-registry v1.13.6/go.mod h1:YhnIzOVjRU2ZwZtzt+fjcjW8ujJaSFynBEu7QVKaSdU= +github.com/operator-framework/operator-registry v1.17.5 h1:LR8m1rFz5Gcyje8WK6iYt+gIhtzqo52zMRALdmTYHT0= +github.com/operator-framework/operator-registry v1.17.5/go.mod h1:sRQIgDMZZdUcmHltzyCnM6RUoDF+WS8Arj1BQIARDS8= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -923,7 +945,6 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -983,7 +1004,6 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= @@ -1031,6 +1051,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -1041,7 +1062,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xlab/treeprint v0.0.0-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= @@ -1062,7 +1082,6 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -1123,17 +1142,21 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0H go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1141,6 +1164,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1157,8 +1181,9 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1224,7 +1249,6 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL 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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1239,6 +1263,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -1329,6 +1355,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1389,7 +1417,6 @@ golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1411,6 +1438,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 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= @@ -1423,7 +1451,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -1446,6 +1474,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= @@ -1474,7 +1503,6 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200701001935-0939c5918c31/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= @@ -1521,8 +1549,9 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1532,7 +1561,6 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= -gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -1544,6 +1572,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1578,13 +1607,17 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s= k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= k8s.io/api v0.22.0-beta.0 h1:Icf4R7+a0zV6GexTqOXlcLw4OojdQVZE263bd4ui8ms= k8s.io/api v0.22.0-beta.0/go.mod h1:qORVa/3lcMBQXyTmjzpk8IN3VRg619iFNr8d16VXkUQ= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= +k8s.io/apiextensions-apiserver v0.20.6/go.mod h1:qO8YMqeMmZH+lV21LUNzV41vfpoE9QVAJRA+MNqj0mo= k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA= k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA= @@ -1592,26 +1625,32 @@ k8s.io/apiextensions-apiserver v0.22.0-beta.0 h1:0w1Z8vtPSH8j0S1ryaztOhwJ1C/4RWT k8s.io/apiextensions-apiserver v0.22.0-beta.0/go.mod h1:Gvf2TX9jNuFdzd+b39kVksy9pEq9rVexezn3SeJoLeI= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= k8s.io/apimachinery v0.22.0-beta.0 h1:y7EnOS9n+ZhCrk9nlwW7kwIr67syKFkGWj/HPAiE+XI= k8s.io/apimachinery v0.22.0-beta.0/go.mod h1:AZCsxGyiXb/4yTvUIiY+4LESjQ12B77LFrbW2xd61is= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY= k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw= k8s.io/apiserver v0.22.0-beta.0 h1:pSXFpHIw3PBA4XNPiwkajD+XyOjJwqSGDCNR8d3orTA= k8s.io/apiserver v0.22.0-beta.0/go.mod h1:8nCnNsRYExj/mPHowit5UvsjbExm1YWojDs4ziem9q4= -k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= +k8s.io/cli-runtime v0.20.6/go.mod h1:JVERW478qcxWrUjJuWQSqyJeiz9QC4T6jmBznHFBC8w= k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs= k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= @@ -1619,20 +1658,24 @@ k8s.io/client-go v0.22.0-beta.0 h1:CMKtGoQPNjt70Ii94mvuRO/eJM1iXuRh+u3V9Fb1ZvM= k8s.io/client-go v0.22.0-beta.0/go.mod h1:h2hyZ6clrIgKFF4Upjz2Epnvo9cq8S7rZfWegGQkNb0= k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= k8s.io/code-generator v0.20.4/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/code-generator v0.20.6/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU= k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U= k8s.io/code-generator v0.22.0-beta.0 h1:fwlAIV7nZmcjHkj4NmIbZCpJyUn2AQGXArvWYVxaND0= k8s.io/code-generator v0.22.0-beta.0/go.mod h1:lBZLjrQ5bAwlmQalYYgV0gH3G7SS+Z2d33ijEte85FY= -k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA= k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc= k8s.io/component-base v0.22.0-beta.0 h1:9FPWLb4nWVyKQDtj7NUEdm+nTSlEdKvLseLAeo10wXg= k8s.io/component-base v0.22.0-beta.0/go.mod h1:/sa2flwcRBe8XTwdrueKBHBrR+J+ptB669U5R4ytRsU= +k8s.io/component-helpers v0.20.6/go.mod h1:d4rFhZS/wxrZCxRiJJiWf1mVGVeMB5/ey3Yv8/rOp78= k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= @@ -1658,10 +1701,10 @@ k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iL k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20210527164424-3c818078ee3d h1:lUK8GPtuJy8ClWZhuvKoaLdKGPLq9H1PxWp7VPBZBkU= k8s.io/kube-openapi v0.0.0-20210527164424-3c818078ee3d/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= +k8s.io/kubectl v0.20.6/go.mod h1:yTCGVrlkBuQhFbKA1R65+lQ9hH7XeyOqUd0FUPFicPg= k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= -k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= +k8s.io/metrics v0.20.6/go.mod h1:d+OAIaXutom9kGWcBit/M8OkDpIzBKTsm47+KcUt7VI= k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -1679,11 +1722,11 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyz sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.20 h1:jLWvYcn/9pCws8p54so9QpxkkL0SWc2fTZTg77NRyhg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.20/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= +sigs.k8s.io/controller-runtime v0.8.0/go.mod h1:v9Lbj5oX443uR7GXYY46E0EE2o7k2YxQ58GxVNeXSW4= sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8= sigs.k8s.io/controller-runtime v0.9.2 h1:MnCAsopQno6+hI9SgJHKddzXpmv2wtouZz6931Eax+Q= sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk= -sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/controller-tools v0.6.0/go.mod h1:baRMVPrctU77F+rfAuH2uPqW93k6yQnZA2dhUOr7ihc= sigs.k8s.io/controller-tools v0.6.1 h1:nODRx2YrSNcaGd+90+CVC9SGEG6ygHlz3nSJmweR5as= sigs.k8s.io/controller-tools v0.6.1/go.mod h1:U6O1RF5w17iX2d+teSXELpJsdexmrTb126DMeJM8r+U= @@ -1700,6 +1743,7 @@ sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.1 h1:nYqY2A6oy37sKLYuSBXuQhbj4JVclzJK13BOIvJG5XU= sigs.k8s.io/structured-merge-diff/v4 v4.1.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= @@ -1707,4 +1751,3 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/vendor/modules.txt b/vendor/modules.txt index 3860cc9dd2..2e97874d94 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -573,7 +573,7 @@ github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/stor github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/version github.com/operator-framework/operator-lifecycle-manager/pkg/version github.com/operator-framework/operator-lifecycle-manager/util/cpb -# github.com/operator-framework/operator-registry v1.13.6 => ./staging/operator-registry +# github.com/operator-framework/operator-registry v1.17.5 => ./staging/operator-registry ## explicit github.com/operator-framework/operator-registry/cmd/configmap-server github.com/operator-framework/operator-registry/cmd/initializer From ba29f0fa0e5ba9b5b76d205c256b335bc9549d45 Mon Sep 17 00:00:00 2001 From: Zvi Cahana Date: Thu, 15 Jul 2021 15:01:07 +0300 Subject: [PATCH 10/30] Regenerate mocks Signed-off-by: Zvi Cahana Upstream-repository: operator-lifecycle-manager Upstream-commit: b393fc5a2a6371261c99cabb009266c95047d047 --- .../pkg/fakes/fake_registry_store.go | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/staging/operator-lifecycle-manager/pkg/fakes/fake_registry_store.go b/staging/operator-lifecycle-manager/pkg/fakes/fake_registry_store.go index 8d27b36632..5894a426ae 100644 --- a/staging/operator-lifecycle-manager/pkg/fakes/fake_registry_store.go +++ b/staging/operator-lifecycle-manager/pkg/fakes/fake_registry_store.go @@ -57,6 +57,20 @@ type FakeQuery struct { result1 *api.Bundle result2 error } + GetBundlePathIfExistsStub func(context.Context, string) (string, error) + getBundlePathIfExistsMutex sync.RWMutex + getBundlePathIfExistsArgsForCall []struct { + arg1 context.Context + arg2 string + } + getBundlePathIfExistsReturns struct { + result1 string + result2 error + } + getBundlePathIfExistsReturnsOnCall map[int]struct { + result1 string + result2 error + } GetBundlePathsForPackageStub func(context.Context, string) ([]string, error) getBundlePathsForPackageMutex sync.RWMutex getBundlePathsForPackageArgsForCall []struct { @@ -331,6 +345,19 @@ type FakeQuery struct { result1 []string result2 error } + ListRegistryBundlesStub func(context.Context) ([]*registry.Bundle, error) + listRegistryBundlesMutex sync.RWMutex + listRegistryBundlesArgsForCall []struct { + arg1 context.Context + } + listRegistryBundlesReturns struct { + result1 []*registry.Bundle + result2 error + } + listRegistryBundlesReturnsOnCall map[int]struct { + result1 []*registry.Bundle + result2 error + } ListTablesStub func(context.Context) ([]string, error) listTablesMutex sync.RWMutex listTablesArgsForCall []struct { @@ -546,6 +573,70 @@ func (fake *FakeQuery) GetBundleForChannelReturnsOnCall(i int, result1 *api.Bund }{result1, result2} } +func (fake *FakeQuery) GetBundlePathIfExists(arg1 context.Context, arg2 string) (string, error) { + fake.getBundlePathIfExistsMutex.Lock() + ret, specificReturn := fake.getBundlePathIfExistsReturnsOnCall[len(fake.getBundlePathIfExistsArgsForCall)] + fake.getBundlePathIfExistsArgsForCall = append(fake.getBundlePathIfExistsArgsForCall, struct { + arg1 context.Context + arg2 string + }{arg1, arg2}) + fake.recordInvocation("GetBundlePathIfExists", []interface{}{arg1, arg2}) + fake.getBundlePathIfExistsMutex.Unlock() + if fake.GetBundlePathIfExistsStub != nil { + return fake.GetBundlePathIfExistsStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundlePathIfExistsReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeQuery) GetBundlePathIfExistsCallCount() int { + fake.getBundlePathIfExistsMutex.RLock() + defer fake.getBundlePathIfExistsMutex.RUnlock() + return len(fake.getBundlePathIfExistsArgsForCall) +} + +func (fake *FakeQuery) GetBundlePathIfExistsCalls(stub func(context.Context, string) (string, error)) { + fake.getBundlePathIfExistsMutex.Lock() + defer fake.getBundlePathIfExistsMutex.Unlock() + fake.GetBundlePathIfExistsStub = stub +} + +func (fake *FakeQuery) GetBundlePathIfExistsArgsForCall(i int) (context.Context, string) { + fake.getBundlePathIfExistsMutex.RLock() + defer fake.getBundlePathIfExistsMutex.RUnlock() + argsForCall := fake.getBundlePathIfExistsArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeQuery) GetBundlePathIfExistsReturns(result1 string, result2 error) { + fake.getBundlePathIfExistsMutex.Lock() + defer fake.getBundlePathIfExistsMutex.Unlock() + fake.GetBundlePathIfExistsStub = nil + fake.getBundlePathIfExistsReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeQuery) GetBundlePathIfExistsReturnsOnCall(i int, result1 string, result2 error) { + fake.getBundlePathIfExistsMutex.Lock() + defer fake.getBundlePathIfExistsMutex.Unlock() + fake.GetBundlePathIfExistsStub = nil + if fake.getBundlePathIfExistsReturnsOnCall == nil { + fake.getBundlePathIfExistsReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.getBundlePathIfExistsReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + func (fake *FakeQuery) GetBundlePathsForPackage(arg1 context.Context, arg2 string) ([]string, error) { fake.getBundlePathsForPackageMutex.Lock() ret, specificReturn := fake.getBundlePathsForPackageReturnsOnCall[len(fake.getBundlePathsForPackageArgsForCall)] @@ -1770,6 +1861,69 @@ func (fake *FakeQuery) ListPackagesReturnsOnCall(i int, result1 []string, result }{result1, result2} } +func (fake *FakeQuery) ListRegistryBundles(arg1 context.Context) ([]*registry.Bundle, error) { + fake.listRegistryBundlesMutex.Lock() + ret, specificReturn := fake.listRegistryBundlesReturnsOnCall[len(fake.listRegistryBundlesArgsForCall)] + fake.listRegistryBundlesArgsForCall = append(fake.listRegistryBundlesArgsForCall, struct { + arg1 context.Context + }{arg1}) + fake.recordInvocation("ListRegistryBundles", []interface{}{arg1}) + fake.listRegistryBundlesMutex.Unlock() + if fake.ListRegistryBundlesStub != nil { + return fake.ListRegistryBundlesStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.listRegistryBundlesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeQuery) ListRegistryBundlesCallCount() int { + fake.listRegistryBundlesMutex.RLock() + defer fake.listRegistryBundlesMutex.RUnlock() + return len(fake.listRegistryBundlesArgsForCall) +} + +func (fake *FakeQuery) ListRegistryBundlesCalls(stub func(context.Context) ([]*registry.Bundle, error)) { + fake.listRegistryBundlesMutex.Lock() + defer fake.listRegistryBundlesMutex.Unlock() + fake.ListRegistryBundlesStub = stub +} + +func (fake *FakeQuery) ListRegistryBundlesArgsForCall(i int) context.Context { + fake.listRegistryBundlesMutex.RLock() + defer fake.listRegistryBundlesMutex.RUnlock() + argsForCall := fake.listRegistryBundlesArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeQuery) ListRegistryBundlesReturns(result1 []*registry.Bundle, result2 error) { + fake.listRegistryBundlesMutex.Lock() + defer fake.listRegistryBundlesMutex.Unlock() + fake.ListRegistryBundlesStub = nil + fake.listRegistryBundlesReturns = struct { + result1 []*registry.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeQuery) ListRegistryBundlesReturnsOnCall(i int, result1 []*registry.Bundle, result2 error) { + fake.listRegistryBundlesMutex.Lock() + defer fake.listRegistryBundlesMutex.Unlock() + fake.ListRegistryBundlesStub = nil + if fake.listRegistryBundlesReturnsOnCall == nil { + fake.listRegistryBundlesReturnsOnCall = make(map[int]struct { + result1 []*registry.Bundle + result2 error + }) + } + fake.listRegistryBundlesReturnsOnCall[i] = struct { + result1 []*registry.Bundle + result2 error + }{result1, result2} +} + func (fake *FakeQuery) ListTables(arg1 context.Context) ([]string, error) { fake.listTablesMutex.Lock() ret, specificReturn := fake.listTablesReturnsOnCall[len(fake.listTablesArgsForCall)] @@ -1842,6 +1996,8 @@ func (fake *FakeQuery) Invocations() map[string][][]interface{} { defer fake.getBundleMutex.RUnlock() fake.getBundleForChannelMutex.RLock() defer fake.getBundleForChannelMutex.RUnlock() + fake.getBundlePathIfExistsMutex.RLock() + defer fake.getBundlePathIfExistsMutex.RUnlock() fake.getBundlePathsForPackageMutex.RLock() defer fake.getBundlePathsForPackageMutex.RUnlock() fake.getBundleThatProvidesMutex.RLock() @@ -1880,6 +2036,8 @@ func (fake *FakeQuery) Invocations() map[string][][]interface{} { defer fake.listImagesMutex.RUnlock() fake.listPackagesMutex.RLock() defer fake.listPackagesMutex.RUnlock() + fake.listRegistryBundlesMutex.RLock() + defer fake.listRegistryBundlesMutex.RUnlock() fake.listTablesMutex.RLock() defer fake.listTablesMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} From e95915d8008ae5198d053e8fbc0d1c8b841a1d1b Mon Sep 17 00:00:00 2001 From: Zvi Cahana Date: Thu, 15 Jul 2021 15:34:41 +0300 Subject: [PATCH 11/30] Update test-scripts check to use go1.16 Signed-off-by: Zvi Cahana Upstream-repository: operator-lifecycle-manager Upstream-commit: 7c481a1c43f999656953c380dcb35e4df3d27df3 --- .../.github/workflows/test-scripts.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/staging/operator-lifecycle-manager/.github/workflows/test-scripts.yml b/staging/operator-lifecycle-manager/.github/workflows/test-scripts.yml index 5ec1f7a31e..1c18d7a9c9 100644 --- a/staging/operator-lifecycle-manager/.github/workflows/test-scripts.yml +++ b/staging/operator-lifecycle-manager/.github/workflows/test-scripts.yml @@ -23,6 +23,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: '~1.16' - run: | sudo apt-get install conntrack curl -sLo minikube "$(curl -sL https://api.github.com/repos/kubernetes/minikube/releases/latest | jq -r '[.assets[] | select(.name == "minikube-linux-amd64")] | first | .browser_download_url')" @@ -34,6 +37,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: '~1.16' - run: | curl -sLo kind "$(curl -sL https://api.github.com/repos/kubernetes-sigs/kind/releases/latest | jq -r '[.assets[] | select(.name == "kind-linux-amd64")] | first | .browser_download_url')" chmod +x kind From 7d0d5724656a4818e278db5d9a1e1543b4ea2eaa Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 16 Jul 2021 10:03:02 -0400 Subject: [PATCH 12/30] Explain unique replaces chain requirement in channel sort errors. The "multiple channel head" error that can be returned from channel sorting has been a source of confusion for users. The error message now explains that a unique replacement chain is required in order to define the relative order between channel entries, and it also provides an abbreviated list of all replacement chains identified, in the form "head...tail" or "singleton". Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 639102545cb6faabe9a1f30970dffca93bfb058a --- .../controller/registry/resolver/resolver.go | 87 ++++--- .../registry/resolver/resolver_test.go | 221 ++++++++++++++---- .../controller/registry/resolver/resolver.go | 87 ++++--- 3 files changed, 282 insertions(+), 113 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index a4473f36bf..8ca81192d8 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "sort" + "strings" "github.com/blang/semver/v4" "github.com/sirupsen/logrus" @@ -237,7 +238,7 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu if i != len(bundles) && bundles[i].bundle.ChannelName == lastChannel { continue } - channel, err := r.sortChannel(bundles[lastIndex:i]) + channel, err := sortChannel(bundles[lastIndex:i]) if err != nil { return nil, err } @@ -610,7 +611,7 @@ func (r *SatResolver) sortBundles(bundles []*Operator) ([]*Operator, error) { return pi.Channel < pj.Channel }) for channel := range partitionedBundles[catalog] { - sorted, err := r.sortChannel(partitionedBundles[catalog][channel]) + sorted, err := sortChannel(partitionedBundles[catalog][channel]) if err != nil { return nil, err } @@ -626,13 +627,15 @@ func (r *SatResolver) sortBundles(bundles []*Operator) ([]*Operator, error) { return all, nil } -// sorts bundle in a channel by replaces -func (r *SatResolver) sortChannel(bundles []*Operator) ([]*Operator, error) { - if len(bundles) <= 1 { +// Sorts bundle in a channel by replaces. All entries in the argument +// are assumed to have the same Package and Channel. +func sortChannel(bundles []*Operator) ([]*Operator, error) { + if len(bundles) < 1 { return bundles, nil } - channel := []*Operator{} + packageName := bundles[0].Package() + channelName := bundles[0].Channel() bundleLookup := map[string]*Operator{} @@ -660,44 +663,64 @@ func (r *SatResolver) sortChannel(bundles []*Operator) ([]*Operator, error) { } } - // a bundle without a replacement is a channel head, but if we find more than one of those something is weird + // a bundle without a replacement is a channel head, but if we + // find more than one of those something is weird headCandidates := []*Operator{} for _, b := range bundles { if _, ok := replacedBy[b]; !ok { headCandidates = append(headCandidates, b) } } + if len(headCandidates) == 0 { + return nil, fmt.Errorf("no channel heads (entries not replaced by another entry) found in channel %q of package %q", channelName, packageName) + } - if len(headCandidates) > 1 { - var names []string - for _, v := range headCandidates { - names = append(names, v.Identifier()) + var chains [][]*Operator + for _, head := range headCandidates { + var chain []*Operator + visited := make(map[*Operator]struct{}) + current := head + skip := false + for { + visited[current] = struct{}{} + if !skip { + chain = append(chain, current) + } + next, ok := replaces[current] + if !ok { + break + } + if _, ok := visited[next]; ok { + return nil, fmt.Errorf("a cycle exists in the chain of replacement beginning with %q in channel %q of package %q", head.Identifier(), channelName, packageName) + } + if _, ok := skipped[current.Identifier()]; ok { + skip = true + } + current = next } - return nil, fmt.Errorf("found multiple channel heads: %v, please check the `replaces`/`skipRange` fields of the operator bundles", names) - - } else if len(headCandidates) < 1 { - return nil, fmt.Errorf("head of channel not found") + chains = append(chains, chain) } - head := headCandidates[0] - current := head - skip := false - for { - if skip == false { - channel = append(channel, current) - } - skip = false - next, ok := replaces[current] - if !ok { - break - } - if _, ok := skipped[current.Identifier()]; ok { - skip = true + if len(chains) > 1 { + schains := make([]string, len(chains)) + for i, chain := range chains { + switch len(chain) { + case 0: + schains[i] = "[]" // Bug? + case 1: + schains[i] = chain[0].Identifier() + default: + schains[i] = fmt.Sprintf("%s...%s", chain[0].Identifier(), chain[len(chain)-1].Identifier()) + } } - current = next + return nil, fmt.Errorf("a unique replacement chain within a channel is required to determine the relative order between channel entries, but %d replacement chains were found in channel %q of package %q: %s", len(schains), channelName, packageName, strings.Join(schains, ", ")) } - // TODO: do we care if the channel doesn't include every bundle in the input? + if len(chains) == 0 { + // Bug? + return nil, fmt.Errorf("found no replacement chains in channel %q of package %q", channelName, packageName) + } - return channel, nil + // TODO: do we care if the channel doesn't include every bundle in the input? + return chains[0], nil } diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go index 22106e1558..73dab52450 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go @@ -1,6 +1,7 @@ package resolver import ( + "errors" "fmt" "testing" @@ -21,11 +22,11 @@ import ( ) func TestSolveOperators(t *testing.T) { - APISet := APISet{opregistry.APIKey{"g", "v", "k", "ks"}: struct{}{}} + APISet := APISet{opregistry.APIKey{Group: "g", Version: "v", Kind: "k", Plural: "ks"}: struct{}{}} Provides := APISet - namespace := "olm" - catalog := registry.CatalogKey{"community", namespace} + const namespace = "test-namespace" + catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} csv := existingOperator(namespace, "packageA.v1", "packageA", "alpha", "", Provides, nil, nil, nil) csvs := []*v1alpha1.ClusterServiceVersion{csv} @@ -35,17 +36,11 @@ func TestSolveOperators(t *testing.T) { fakeNamespacedOperatorCache := NamespacedOperatorCache{ snapshots: map[registry.CatalogKey]*CatalogSnapshot{ - registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }: { - key: registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }, + catalog: { + key: catalog, operators: []*Operator{ - genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", nil, nil, nil, "", false), - genOperator("packageB.v1", "1.0.1", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false), + genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + genOperator("packageB.v1", "1.0.1", "", "packageB", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), }, }, }, @@ -55,12 +50,11 @@ func TestSolveOperators(t *testing.T) { log: logrus.New(), } - operators, err := satResolver.SolveOperators([]string{"olm"}, csvs, subs) + operators, err := satResolver.SolveOperators([]string{namespace}, csvs, subs) assert.NoError(t, err) expected := OperatorSet{ - "packageA.v1": genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", nil, nil, nil, "", false), - "packageB.v1": genOperator("packageB.v1", "1.0.1", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false), + "packageB.v1": genOperator("packageB.v1", "1.0.1", "", "packageB", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), } require.EqualValues(t, expected, operators) } @@ -117,16 +111,10 @@ func TestSolveOperators_MultipleChannels(t *testing.T) { fakeNamespacedOperatorCache := NamespacedOperatorCache{ snapshots: map[registry.CatalogKey]*CatalogSnapshot{ - registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }: { - key: registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }, + catalog: { + key: catalog, operators: []*Operator{ - genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", nil, nil, nil, "", false), + genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", "olm", nil, nil, nil, "", false), genOperator("packageB.v1", "1.0.0", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false), genOperator("packageB.v1", "1.0.0", "", "packageB", "beta", "community", "olm", nil, nil, nil, "", false), }, @@ -141,10 +129,9 @@ func TestSolveOperators_MultipleChannels(t *testing.T) { operators, err := satResolver.SolveOperators([]string{"olm"}, csvs, subs) assert.NoError(t, err) expected := OperatorSet{ - "packageA.v1": genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", nil, nil, nil, "", false), "packageB.v1": genOperator("packageB.v1", "1.0.0", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false), } - assert.Equal(t, 2, len(operators)) + assert.Len(t, operators, 1) for k, e := range expected { assert.EqualValues(t, e, operators[k]) } @@ -373,7 +360,7 @@ func TestSolveOperators_CatsrcPrioritySorting(t *testing.T) { Name: "community", }, operators: []*Operator{ - genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", namespace, nil, + genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", namespace, nil, nil, opToAddVersionDeps, "", false), }, }, @@ -415,7 +402,7 @@ func TestSolveOperators_CatsrcPrioritySorting(t *testing.T) { operators, err := satResolver.SolveOperators([]string{"olm"}, []*v1alpha1.ClusterServiceVersion{}, subs) assert.NoError(t, err) expected := OperatorSet{ - "packageA.v1": genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", + "packageA.v1": genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", "olm", nil, nil, opToAddVersionDeps, "", false), "packageB.v1": genOperator("packageB.v1", "0.0.1", "", "packageB", "alpha", "high-priority-operator", "olm", nil, nil, nil, "", false), @@ -448,7 +435,7 @@ func TestSolveOperators_CatsrcPrioritySorting(t *testing.T) { operators, err = satResolver.SolveOperators([]string{"olm"}, []*v1alpha1.ClusterServiceVersion{}, subs) assert.NoError(t, err) expected = OperatorSet{ - "packageA.v1": genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", + "packageA.v1": genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", "olm", nil, nil, opToAddVersionDeps, "", false), "packageB.v1": genOperator("packageB.v1", "0.0.1", "", "packageB", "alpha", "community-operator", "olm", nil, nil, nil, "", false), @@ -468,7 +455,7 @@ func TestSolveOperators_CatsrcPrioritySorting(t *testing.T) { Name: "community", }, operators: []*Operator{ - genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", namespace, nil, + genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", namespace, nil, nil, opToAddVersionDeps, "", false), genOperator("packageB.v1", "0.0.1", "", "packageB", "alpha", "community", namespace, nil, nil, nil, "", false), @@ -482,7 +469,7 @@ func TestSolveOperators_CatsrcPrioritySorting(t *testing.T) { operators, err = satResolver.SolveOperators([]string{"olm"}, []*v1alpha1.ClusterServiceVersion{}, subs) assert.NoError(t, err) expected = OperatorSet{ - "packageA.v1": genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", "community", "olm", + "packageA.v1": genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", "community", "olm", nil, nil, opToAddVersionDeps, "", false), "packageB.v1": genOperator("packageB.v1", "0.0.1", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false), @@ -1356,7 +1343,7 @@ func TestSolveOperators_WithoutDeprecated(t *testing.T) { catalog: { key: catalog, operators: []*Operator{ - genOperator("packageA.v1", "0.0.1", "packageA.v1", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", true), + genOperator("packageA.v1", "0.0.1", "", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", true), }, }, }, @@ -1423,9 +1410,9 @@ func TestSolveOperators_WithSkipsAndStartingCSV(t *testing.T) { op1 := genOperator("packageA.v1", "1.0.0", "", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) op2 := genOperator("packageA.v2", "2.0.0", "packageA.v1", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) op3 := genOperator("packageA.v3", "3.0.0", "packageA.v2", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) - op4 := genOperator("packageA.v4", "4.0.0", "packageA.v2", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) + op4 := genOperator("packageA.v4", "4.0.0", "packageA.v3", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) op4.skips = []string{"packageA.v3"} - op5 := genOperator("packageA.v5", "5.0.0", "packageA.v1", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) + op5 := genOperator("packageA.v5", "5.0.0", "packageA.v4", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) op5.skips = []string{"packageA.v2", "packageA.v3", "packageA.v4"} op6 := genOperator("packageA.v6", "6.0.0", "packageA.v5", "packageA", "alpha", "community", "olm", nil, Provides, nil, "", false) @@ -1461,26 +1448,20 @@ func TestSolveOperators_WithSkipsAndStartingCSV(t *testing.T) { } func TestSolveOperators_WithSkips(t *testing.T) { - namespace := "olm" - catalog := registry.CatalogKey{"community", namespace} + const namespace = "test-namespace" + catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} newSub := newSub(namespace, "packageB", "alpha", catalog) subs := []*v1alpha1.Subscription{newSub} - opB := genOperator("packageB.v1", "1.0.0", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false) - opB2 := genOperator("packageB.v2", "2.0.0", "", "packageB", "alpha", "community", "olm", nil, nil, nil, "", false) + opB := genOperator("packageB.v1", "1.0.0", "", "packageB", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false) + opB2 := genOperator("packageB.v2", "2.0.0", "", "packageB", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false) opB2.skips = []string{"packageB.v1"} fakeNamespacedOperatorCache := NamespacedOperatorCache{ snapshots: map[registry.CatalogKey]*CatalogSnapshot{ - registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }: { - key: registry.CatalogKey{ - Namespace: "olm", - Name: "community", - }, + catalog: { + key: catalog, operators: []*Operator{ opB, opB2, }, @@ -1492,7 +1473,7 @@ func TestSolveOperators_WithSkips(t *testing.T) { log: logrus.New(), } - operators, err := satResolver.SolveOperators([]string{"olm"}, nil, subs) + operators, err := satResolver.SolveOperators([]string{namespace}, nil, subs) assert.NoError(t, err) expected := OperatorSet{ "packageB.v2": opB2, @@ -1536,7 +1517,6 @@ func TestSolveOperatorsWithClusterServiceVersionHavingDependency(t *testing.T) { operators, err := r.SolveOperators([]string{namespace}, csvs, subs) assert.NoError(t, err) - //expected := OperatorSet{} require.Empty(t, operators) } @@ -1742,3 +1722,146 @@ func TestInferProperties(t *testing.T) { }) } } + +func TestSortChannel(t *testing.T) { + for _, tc := range []struct { + Name string + In []*Operator + Out []*Operator + Err error + }{ + { + Name: "wrinkle-free", + In: []*Operator{ + { + name: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "a", + replaces: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + }, + Out: []*Operator{ + { + name: "a", + replaces: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + }, + }, + { + Name: "empty", + In: nil, + Out: nil, + }, + { + Name: "replacement cycle", + In: []*Operator{ + { + name: "a", + replaces: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "b", + replaces: "a", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + }, + Err: errors.New(`no channel heads (entries not replaced by another entry) found in channel "channel" of package "package"`), + }, + { + Name: "replacement cycle", + In: []*Operator{ + { + name: "a", + replaces: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "b", + replaces: "c", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "c", + replaces: "b", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + }, + Err: errors.New(`a cycle exists in the chain of replacement beginning with "a" in channel "channel" of package "package"`), + }, + { + Name: "two replaces chains", + In: []*Operator{ + { + name: "a", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "b", + replaces: "c", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + { + name: "c", + bundle: &api.Bundle{ + PackageName: "package", + ChannelName: "channel", + }, + }, + }, + Err: errors.New(`a unique replacement chain within a channel is required to determine the relative order between channel entries, but 2 replacement chains were found in channel "channel" of package "package": a, b...c`), + }, + } { + t.Run(tc.Name, func(t *testing.T) { + assert := assert.New(t) + actual, err := sortChannel(tc.In) + if tc.Err == nil { + assert.NoError(err) + } else { + assert.EqualError(err, tc.Err.Error()) + } + assert.Equal(tc.Out, actual) + }) + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index a4473f36bf..8ca81192d8 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "sort" + "strings" "github.com/blang/semver/v4" "github.com/sirupsen/logrus" @@ -237,7 +238,7 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu if i != len(bundles) && bundles[i].bundle.ChannelName == lastChannel { continue } - channel, err := r.sortChannel(bundles[lastIndex:i]) + channel, err := sortChannel(bundles[lastIndex:i]) if err != nil { return nil, err } @@ -610,7 +611,7 @@ func (r *SatResolver) sortBundles(bundles []*Operator) ([]*Operator, error) { return pi.Channel < pj.Channel }) for channel := range partitionedBundles[catalog] { - sorted, err := r.sortChannel(partitionedBundles[catalog][channel]) + sorted, err := sortChannel(partitionedBundles[catalog][channel]) if err != nil { return nil, err } @@ -626,13 +627,15 @@ func (r *SatResolver) sortBundles(bundles []*Operator) ([]*Operator, error) { return all, nil } -// sorts bundle in a channel by replaces -func (r *SatResolver) sortChannel(bundles []*Operator) ([]*Operator, error) { - if len(bundles) <= 1 { +// Sorts bundle in a channel by replaces. All entries in the argument +// are assumed to have the same Package and Channel. +func sortChannel(bundles []*Operator) ([]*Operator, error) { + if len(bundles) < 1 { return bundles, nil } - channel := []*Operator{} + packageName := bundles[0].Package() + channelName := bundles[0].Channel() bundleLookup := map[string]*Operator{} @@ -660,44 +663,64 @@ func (r *SatResolver) sortChannel(bundles []*Operator) ([]*Operator, error) { } } - // a bundle without a replacement is a channel head, but if we find more than one of those something is weird + // a bundle without a replacement is a channel head, but if we + // find more than one of those something is weird headCandidates := []*Operator{} for _, b := range bundles { if _, ok := replacedBy[b]; !ok { headCandidates = append(headCandidates, b) } } + if len(headCandidates) == 0 { + return nil, fmt.Errorf("no channel heads (entries not replaced by another entry) found in channel %q of package %q", channelName, packageName) + } - if len(headCandidates) > 1 { - var names []string - for _, v := range headCandidates { - names = append(names, v.Identifier()) + var chains [][]*Operator + for _, head := range headCandidates { + var chain []*Operator + visited := make(map[*Operator]struct{}) + current := head + skip := false + for { + visited[current] = struct{}{} + if !skip { + chain = append(chain, current) + } + next, ok := replaces[current] + if !ok { + break + } + if _, ok := visited[next]; ok { + return nil, fmt.Errorf("a cycle exists in the chain of replacement beginning with %q in channel %q of package %q", head.Identifier(), channelName, packageName) + } + if _, ok := skipped[current.Identifier()]; ok { + skip = true + } + current = next } - return nil, fmt.Errorf("found multiple channel heads: %v, please check the `replaces`/`skipRange` fields of the operator bundles", names) - - } else if len(headCandidates) < 1 { - return nil, fmt.Errorf("head of channel not found") + chains = append(chains, chain) } - head := headCandidates[0] - current := head - skip := false - for { - if skip == false { - channel = append(channel, current) - } - skip = false - next, ok := replaces[current] - if !ok { - break - } - if _, ok := skipped[current.Identifier()]; ok { - skip = true + if len(chains) > 1 { + schains := make([]string, len(chains)) + for i, chain := range chains { + switch len(chain) { + case 0: + schains[i] = "[]" // Bug? + case 1: + schains[i] = chain[0].Identifier() + default: + schains[i] = fmt.Sprintf("%s...%s", chain[0].Identifier(), chain[len(chain)-1].Identifier()) + } } - current = next + return nil, fmt.Errorf("a unique replacement chain within a channel is required to determine the relative order between channel entries, but %d replacement chains were found in channel %q of package %q: %s", len(schains), channelName, packageName, strings.Join(schains, ", ")) } - // TODO: do we care if the channel doesn't include every bundle in the input? + if len(chains) == 0 { + // Bug? + return nil, fmt.Errorf("found no replacement chains in channel %q of package %q", channelName, packageName) + } - return channel, nil + // TODO: do we care if the channel doesn't include every bundle in the input? + return chains[0], nil } From aad1cb2f07c1fb388daa904a012ac762e122af8a Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 16 Jul 2021 14:16:07 -0400 Subject: [PATCH 13/30] Correctly omit skipped channel entries during resolution. A behavior was added with the intention of preventing the installation of channel entries that are skipped by other entries, but in practice it was omitting entries that were replaced by skipped entries. This is fixed. There are now unit test cases and one higher-level test for this behavior. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 0bb8c1ea9741071830711e3517f39e264f561154 --- .../controller/registry/resolver/resolver.go | 6 +- .../registry/resolver/resolver_test.go | 80 +++++++++++++++++++ .../controller/registry/resolver/resolver.go | 6 +- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index 8ca81192d8..668f9be04f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -680,10 +680,9 @@ func sortChannel(bundles []*Operator) ([]*Operator, error) { var chain []*Operator visited := make(map[*Operator]struct{}) current := head - skip := false for { visited[current] = struct{}{} - if !skip { + if _, ok := skipped[current.Identifier()]; !ok { chain = append(chain, current) } next, ok := replaces[current] @@ -693,9 +692,6 @@ func sortChannel(bundles []*Operator) ([]*Operator, error) { if _, ok := visited[next]; ok { return nil, fmt.Errorf("a cycle exists in the chain of replacement beginning with %q in channel %q of package %q", head.Identifier(), channelName, packageName) } - if _, ok := skipped[current.Identifier()]; ok { - skip = true - } current = next } chains = append(chains, chain) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go index 73dab52450..aa288d0946 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go @@ -1481,6 +1481,38 @@ func TestSolveOperators_WithSkips(t *testing.T) { require.EqualValues(t, expected, operators) } +func TestSolveOperatorsWithSkipsPreventingSelection(t *testing.T) { + const namespace = "test-namespace" + catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} + gvks := APISet{opregistry.APIKey{Group: "g", Version: "v", Kind: "k", Plural: "ks"}: struct{}{}} + + // Subscription candidate a-1 requires a GVK provided + // exclusively by b-1, but b-1 is skipped by b-3 and can't be + // chosen. + subs := []*v1alpha1.Subscription{newSub(namespace, "a", "channel", catalog)} + a1 := genOperator("a-1", "1.0.0", "", "a", "channel", catalog.Name, catalog.Namespace, gvks, nil, nil, "", false) + b3 := genOperator("b-3", "3.0.0", "b-2", "b", "channel", catalog.Name, catalog.Namespace, nil, nil, nil, "", false) + b3.skips = []string{"b-1"} + b2 := genOperator("b-2", "2.0.0", "b-1", "b", "channel", catalog.Name, catalog.Namespace, nil, nil, nil, "", false) + b1 := genOperator("b-1", "1.0.0", "", "b", "channel", catalog.Name, catalog.Namespace, nil, gvks, nil, "", false) + + logger, _ := test.NewNullLogger() + satResolver := SatResolver{ + cache: getFakeOperatorCache(NamespacedOperatorCache{ + snapshots: map[registry.CatalogKey]*CatalogSnapshot{ + catalog: { + key: catalog, + operators: []*Operator{a1, b3, b2, b1}, + }, + }, + }), + log: logger, + } + + _, err := satResolver.SolveOperators([]string{namespace}, nil, subs) + assert.IsType(t, solver.NotSatisfiable{}, err) +} + func TestSolveOperatorsWithClusterServiceVersionHavingDependency(t *testing.T) { const namespace = "test-namespace" catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} @@ -1824,6 +1856,54 @@ func TestSortChannel(t *testing.T) { }, Err: errors.New(`a cycle exists in the chain of replacement beginning with "a" in channel "channel" of package "package"`), }, + { + Name: "skipped and replaced entry omitted", + In: []*Operator{ + { + name: "a", + replaces: "b", + skips: []string{"b"}, + }, + { + name: "b", + }, + }, + Out: []*Operator{ + { + name: "a", + replaces: "b", + skips: []string{"b"}, + }, + }, + }, + { + Name: "skipped entry omitted", + In: []*Operator{ + { + name: "a", + replaces: "b", + skips: []string{"c"}, + }, + { + name: "b", + replaces: "c", + }, + { + name: "c", + }, + }, + Out: []*Operator{ + { + name: "a", + replaces: "b", + skips: []string{"c"}, + }, + { + name: "b", + replaces: "c", + }, + }, + }, { Name: "two replaces chains", In: []*Operator{ diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index 8ca81192d8..668f9be04f 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -680,10 +680,9 @@ func sortChannel(bundles []*Operator) ([]*Operator, error) { var chain []*Operator visited := make(map[*Operator]struct{}) current := head - skip := false for { visited[current] = struct{}{} - if !skip { + if _, ok := skipped[current.Identifier()]; !ok { chain = append(chain, current) } next, ok := replaces[current] @@ -693,9 +692,6 @@ func sortChannel(bundles []*Operator) ([]*Operator, error) { if _, ok := visited[next]; ok { return nil, fmt.Errorf("a cycle exists in the chain of replacement beginning with %q in channel %q of package %q", head.Identifier(), channelName, packageName) } - if _, ok := skipped[current.Identifier()]; ok { - skip = true - } current = next } chains = append(chains, chain) From 9951b9553ffc4274006af87fd900e4f5017d973e Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 16 Jul 2021 16:45:08 -0400 Subject: [PATCH 14/30] Fix ClusterOperator selector for excluding copied CSVs. The function that generated the selector had been returning a selector that matches everything. There was no functional impact because there's an additional client-side filter that discards objects based on CSV.IsCopied(). Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 0f58a2c7d78cceb22e8ccf6b3b00c1520987a7d4 --- .../controller/operators/openshift/helpers.go | 6 +---- .../operators/openshift/helpers_test.go | 23 +++++++++++++++++++ .../controller/operators/openshift/helpers.go | 6 +---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go index a30ab420f7..4dfd76c904 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go @@ -241,11 +241,7 @@ func notCopiedSelector() (labels.Selector, error) { if err != nil { return nil, err } - - selector := labels.NewSelector() - selector.Add(*requirement) - - return selector, nil + return labels.NewSelector().Add(*requirement), nil } func olmOperatorRelatedObjects(ctx context.Context, cli client.Client, namespace string) ([]configv1.ObjectReference, error) { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go index 6ce1230834..92c7a22f3f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go @@ -8,6 +8,7 @@ import ( configv1 "github.com/openshift/api/config/v1" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -602,3 +603,25 @@ func TestMaxOpenShiftVersion(t *testing.T) { }) } } + +func TestNotCopiedSelector(t *testing.T) { + for _, tc := range []struct { + Labels labels.Set + Matches bool + }{ + { + Labels: labels.Set{operatorsv1alpha1.CopiedLabelKey: ""}, + Matches: false, + }, + { + Labels: labels.Set{}, + Matches: true, + }, + } { + t.Run(tc.Labels.String(), func(t *testing.T) { + selector, err := notCopiedSelector() + require.NoError(t, err) + require.Equal(t, tc.Matches, selector.Matches(tc.Labels)) + }) + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go index a30ab420f7..4dfd76c904 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go @@ -241,11 +241,7 @@ func notCopiedSelector() (labels.Selector, error) { if err != nil { return nil, err } - - selector := labels.NewSelector() - selector.Add(*requirement) - - return selector, nil + return labels.NewSelector().Add(*requirement), nil } func olmOperatorRelatedObjects(ctx context.Context, cli client.Client, namespace string) ([]configv1.ObjectReference, error) { From d8e537ed363682d849decdc18def4ef5ae2c819f Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Fri, 16 Jul 2021 17:17:49 -0400 Subject: [PATCH 15/30] Don't cache copied CSVs in the controller-runtime-based controllers. Only the main controller (i.e., the controller responsible for reconciling ClusterServiceVersions) needs to watch copied ClusterServiceVersions. The OperatorCondition and Operator controllers -- which coincidentally maintain separate caches -- are not interested in copied CSVs, so all copied CSVs can be excluded via from their cache using a label selector. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: e641e7695c944b3a1eef6ce425cd748f2843ddc9 --- .../cmd/olm/manager.go | 31 +++++++++++++++++-- .../cmd/olm/manager.go | 31 +++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/staging/operator-lifecycle-manager/cmd/olm/manager.go b/staging/operator-lifecycle-manager/cmd/olm/manager.go index f01b6c77c6..7f6b89012c 100644 --- a/staging/operator-lifecycle-manager/cmd/olm/manager.go +++ b/staging/operator-lifecycle-manager/cmd/olm/manager.go @@ -2,31 +2,58 @@ package main import ( "context" - "k8s.io/apimachinery/pkg/labels" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/selection" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators" "github.com/operator-framework/operator-lifecycle-manager/pkg/feature" ) +var ( + copiedLabelDoesNotExist labels.Selector +) + +func init() { + requirement, err := labels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.DoesNotExist, nil) + if err != nil { + panic(err) + } + copiedLabelDoesNotExist = labels.NewSelector().Add(*requirement) +} + func Manager(ctx context.Context, debug bool) (ctrl.Manager, error) { ctrl.SetLogger(zap.New(zap.UseDevMode(debug))) setupLog := ctrl.Log.WithName("setup").V(1) - // Setup a Manager + scheme := runtime.NewScheme() + if err := operators.AddToScheme(scheme); err != nil { + // ctrl.NewManager needs the Scheme to be populated + // up-front so that the NewCache implementation we + // provide can configure custom cache behavior on + // non-core types. + return nil, err + } + setupLog.Info("configuring manager") mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, MetricsBindAddress: "0", // TODO(njhale): Enable metrics on non-conflicting port (not 8080) NewCache: cache.BuilderWithOptions(cache.Options{ SelectorsByObject: cache.SelectorsByObject{ &corev1.Secret{}: { Label: labels.SelectorFromValidatedSet(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}), }, + &operatorsv1alpha1.ClusterServiceVersion{}: { + Label: copiedLabelDoesNotExist, + }, }, }), }) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go index f01b6c77c6..7f6b89012c 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go @@ -2,31 +2,58 @@ package main import ( "context" - "k8s.io/apimachinery/pkg/labels" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/selection" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators" "github.com/operator-framework/operator-lifecycle-manager/pkg/feature" ) +var ( + copiedLabelDoesNotExist labels.Selector +) + +func init() { + requirement, err := labels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.DoesNotExist, nil) + if err != nil { + panic(err) + } + copiedLabelDoesNotExist = labels.NewSelector().Add(*requirement) +} + func Manager(ctx context.Context, debug bool) (ctrl.Manager, error) { ctrl.SetLogger(zap.New(zap.UseDevMode(debug))) setupLog := ctrl.Log.WithName("setup").V(1) - // Setup a Manager + scheme := runtime.NewScheme() + if err := operators.AddToScheme(scheme); err != nil { + // ctrl.NewManager needs the Scheme to be populated + // up-front so that the NewCache implementation we + // provide can configure custom cache behavior on + // non-core types. + return nil, err + } + setupLog.Info("configuring manager") mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, MetricsBindAddress: "0", // TODO(njhale): Enable metrics on non-conflicting port (not 8080) NewCache: cache.BuilderWithOptions(cache.Options{ SelectorsByObject: cache.SelectorsByObject{ &corev1.Secret{}: { Label: labels.SelectorFromValidatedSet(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}), }, + &operatorsv1alpha1.ClusterServiceVersion{}: { + Label: copiedLabelDoesNotExist, + }, }, }), }) From 92abe27ba64172bf378502dc7eed3a50d3bad120 Mon Sep 17 00:00:00 2001 From: Anik Bhattacharjee Date: Fri, 16 Jul 2021 16:21:38 -0400 Subject: [PATCH 16/30] feat(sub): Include IP failure condition message in sub status condition Currently when an InstallPlan fails, due to bundle unpacking error is pending due to errors like invalid operatorgroup, or pending bundle unpacking job the reason is propagated to the Subscription that owns it. The message for the failure is however missing from the Subscription condition. eg ``` kind: Subscription status: conditions: - lastTransitionTime: "2021-07-07T17:55:20Z" reason: Installing status: "True" type: InstallPlanPending ``` This PR propagates the message assosiated with the reason in the InstallPlan condition when an InstallPlan is either pending, or has failed permanantly. eg ``` kind: Subscription status: conditions: - lastTransitionTime: "2021-07-07T17:55:20Z" message: no operator group found that is managing this namespace reason: Installing status: "True" type: InstallPlanPending ``` Signed-off-by: Anik Bhattacharjee Upstream-repository: operator-lifecycle-manager Upstream-commit: 303608dbe3c9cbfe4679bafc43a6acafea9f7e9e --- .../operators/catalog/subscription/state.go | 24 ++++++++++++++++++- .../catalog/subscription/state_test.go | 23 ++++++++++++++++-- .../operators/catalog/subscription/state.go | 24 ++++++++++++++++++- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go index f5da96614a..e7280e39b2 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go @@ -1,6 +1,7 @@ package subscription import ( + "bytes" "context" "fmt" @@ -452,7 +453,7 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl if cond.Reason == "" { cond.Reason = string(phase) } - + cond.Message = extractMessage(status) cond.Type = v1alpha1.SubscriptionInstallPlanPending cond.Status = corev1.ConditionTrue out.Status.SetCondition(cond) @@ -472,6 +473,7 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl } cond.Type = v1alpha1.SubscriptionInstallPlanFailed + cond.Message = extractMessage(status) cond.Status = corev1.ConditionTrue out.Status.SetCondition(cond) @@ -508,6 +510,26 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl return known, nil } +func extractMessage(status *v1alpha1.InstallPlanStatus) string { + str := "" + if len(status.BundleLookups) > 0 { + var b bytes.Buffer + for _, lookup := range status.BundleLookups { + if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown { + b.WriteString(cond.Message) + b.WriteString(".") + } + } + str = b.String() + } + if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown { + if cond.Message != "" { + str = cond.Message + } + } + return str +} + type installPlanKnownState struct { InstallPlanReferencedState } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go index 3ba23f4fdf..4228216499 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go @@ -1336,6 +1336,14 @@ func TestCheckInstallPlanStatus(t *testing.T) { now: &now, status: &v1alpha1.InstallPlanStatus{ Phase: v1alpha1.InstallPlanPhaseInstalling, + Conditions: []v1alpha1.InstallPlanCondition{ + { + Type: v1alpha1.InstallPlanInstalled, + Message: "no operatorgroup found that is managing this namespace", + Reason: v1alpha1.InstallPlanConditionReason("Installing"), + Status: corev1.ConditionFalse, + }, + }, }, }, want: want{ @@ -1346,7 +1354,7 @@ func TestCheckInstallPlanStatus(t *testing.T) { }, Status: v1alpha1.SubscriptionStatus{ Conditions: []v1alpha1.SubscriptionCondition{ - planPendingCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanPhaseInstalling), "", &now), + planPendingCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanPhaseInstalling), "no operatorgroup found that is managing this namespace", &now), }, LastUpdated: now, }, @@ -1535,6 +1543,17 @@ func TestCheckInstallPlanStatus(t *testing.T) { Reason: v1alpha1.InstallPlanReasonComponentFailed, }, }, + BundleLookups: []v1alpha1.BundleLookup{ + { + Conditions: []v1alpha1.BundleLookupCondition{ + { + Type: v1alpha1.BundleLookupPending, + Status: corev1.ConditionTrue, + Message: "unpack job not completed: Unpack pod(olm/c5a4) container(pull) is pending. Reason: ImagePullBackOff, Message: Back-off pulling image", + }, + }, + }, + }, }, }, want: want{ @@ -1545,7 +1564,7 @@ func TestCheckInstallPlanStatus(t *testing.T) { }, Status: v1alpha1.SubscriptionStatus{ Conditions: []v1alpha1.SubscriptionCondition{ - planFailedCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanReasonComponentFailed), "", &now), + planFailedCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanReasonComponentFailed), "unpack job not completed: Unpack pod(olm/c5a4) container(pull) is pending. Reason: ImagePullBackOff, Message: Back-off pulling image.", &now), }, LastUpdated: now, }, diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go index f5da96614a..e7280e39b2 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go @@ -1,6 +1,7 @@ package subscription import ( + "bytes" "context" "fmt" @@ -452,7 +453,7 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl if cond.Reason == "" { cond.Reason = string(phase) } - + cond.Message = extractMessage(status) cond.Type = v1alpha1.SubscriptionInstallPlanPending cond.Status = corev1.ConditionTrue out.Status.SetCondition(cond) @@ -472,6 +473,7 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl } cond.Type = v1alpha1.SubscriptionInstallPlanFailed + cond.Message = extractMessage(status) cond.Status = corev1.ConditionTrue out.Status.SetCondition(cond) @@ -508,6 +510,26 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl return known, nil } +func extractMessage(status *v1alpha1.InstallPlanStatus) string { + str := "" + if len(status.BundleLookups) > 0 { + var b bytes.Buffer + for _, lookup := range status.BundleLookups { + if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown { + b.WriteString(cond.Message) + b.WriteString(".") + } + } + str = b.String() + } + if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown { + if cond.Message != "" { + str = cond.Message + } + } + return str +} + type installPlanKnownState struct { InstallPlanReferencedState } From c23e5ec562be343aa6d9aff28280bc8dd1156111 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 19 Jul 2021 09:51:28 -0400 Subject: [PATCH 17/30] add a resolver test for completely disjoint graphs within a channel Signed-off-by: Evan Upstream-repository: operator-lifecycle-manager Upstream-commit: 48115e0f7fce4beb9f50d2d7fd7e2f59380186f8 --- .../registry/resolver/resolver_test.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go index aa288d0946..b954425930 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go @@ -59,6 +59,35 @@ func TestSolveOperators(t *testing.T) { require.EqualValues(t, expected, operators) } +func TestDisjointChannelGraph(t *testing.T) { + const namespace = "test-namespace" + catalog := registry.CatalogKey{Name: "test-catalog", Namespace: namespace} + + newSub := newSub(namespace, "packageA", "alpha", catalog) + subs := []*v1alpha1.Subscription{newSub} + + fakeNamespacedOperatorCache := NamespacedOperatorCache{ + snapshots: map[registry.CatalogKey]*CatalogSnapshot{ + catalog: { + key: catalog, + operators: []*Operator{ + genOperator("packageA.side1.v1", "0.0.1", "", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + genOperator("packageA.side1.v2", "0.0.2", "packageA.side1.v1", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + genOperator("packageA.side2.v1", "1.0.0", "", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + genOperator("packageA.side2.v2", "2.0.0", "packageA.side2.v1", "packageA", "alpha", catalog.Name, catalog.Namespace, nil, nil, nil, "", false), + }, + }, + }, + } + satResolver := SatResolver{ + cache: getFakeOperatorCache(fakeNamespacedOperatorCache), + log: logrus.New(), + } + + _, err := satResolver.SolveOperators([]string{namespace}, nil, subs) + require.Error(t, err, "a unique replacement chain within a channel is required to determine the relative order between channel entries, but 2 replacement chains were found in channel \"alpha\" of package \"packageA\": packageA.side1.v2...packageA.side1.v1, packageA.side2.v2...packageA.side2.v1") +} + func TestPropertiesAnnotationHonored(t *testing.T) { const ( namespace = "olm" From 0a07b46243e4c0bb2d6c78219151ba295b4c7415 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Tue, 6 Jul 2021 16:12:43 -0400 Subject: [PATCH 18/30] Add list subcommands for packages, channels, and bundles Also ensure that properties are rendered in a consistent ordering Signed-off-by: Joe Lanford Upstream-repository: operator-registry Upstream-commit: bb92cc88e4678faa723bac4a8f11d5451c66854b --- .../operator-registry/cmd/opm/alpha/cmd.go | 3 +- .../cmd/opm/alpha/list/cmd.go | 107 +++++ .../operator-registry/internal/action/list.go | 227 +++++++++ .../internal/action/list_test.go | 117 +++++ .../internal/action/render.go | 81 +++- .../internal/action/render_test.go | 434 ++++++++++++++---- .../manifests/foo.v0.1.0.csv.yaml | 1 + .../manifests/foo.v0.2.0.csv.yaml | 1 + .../metadata/annotations.yaml | 2 +- .../foo-index-v0.2.0-declcfg/foo/index.yaml | 8 +- .../internal/declcfg/helpers_test.go | 6 + .../internal/declcfg/model_to_declcfg.go | 8 + .../internal/declcfg/write_test.go | 142 +++--- .../operator-registry/internal/model/model.go | 2 + .../operator-registry/cmd/opm/alpha/cmd.go | 3 +- .../cmd/opm/alpha/list/cmd.go | 107 +++++ .../operator-registry/internal/action/list.go | 227 +++++++++ .../internal/action/render.go | 81 +++- .../manifests/foo.v0.1.0.csv.yaml | 1 + .../manifests/foo.v0.2.0.csv.yaml | 1 + .../metadata/annotations.yaml | 2 +- .../foo-index-v0.2.0-declcfg/foo/index.yaml | 8 +- .../internal/declcfg/model_to_declcfg.go | 8 + .../operator-registry/internal/model/model.go | 2 + vendor/modules.txt | 1 + 25 files changed, 1369 insertions(+), 211 deletions(-) create mode 100644 staging/operator-registry/cmd/opm/alpha/list/cmd.go create mode 100644 staging/operator-registry/internal/action/list.go create mode 100644 staging/operator-registry/internal/action/list_test.go create mode 100644 vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/list/cmd.go create mode 100644 vendor/github.com/operator-framework/operator-registry/internal/action/list.go diff --git a/staging/operator-registry/cmd/opm/alpha/cmd.go b/staging/operator-registry/cmd/opm/alpha/cmd.go index 323a19f817..42e50e3ddf 100644 --- a/staging/operator-registry/cmd/opm/alpha/cmd.go +++ b/staging/operator-registry/cmd/opm/alpha/cmd.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle" + "github.com/operator-framework/operator-registry/cmd/opm/alpha/list" ) func NewCmd() *cobra.Command { @@ -13,6 +14,6 @@ func NewCmd() *cobra.Command { Short: "Run an alpha subcommand", } - runCmd.AddCommand(bundle.NewCmd()) + runCmd.AddCommand(bundle.NewCmd(), list.NewCmd()) return runCmd } diff --git a/staging/operator-registry/cmd/opm/alpha/list/cmd.go b/staging/operator-registry/cmd/opm/alpha/list/cmd.go new file mode 100644 index 0000000000..8309b089a1 --- /dev/null +++ b/staging/operator-registry/cmd/opm/alpha/list/cmd.go @@ -0,0 +1,107 @@ +package list + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "github.com/operator-framework/operator-registry/internal/action" +) + +const humanReadabilityOnlyNote = `NOTE: This is meant to be used for convenience and human-readability only. The +CLI and output format are subject to change, so it is not recommended to depend +on the output in any programs or scripts. Use the "render" subcommand to do +more complex processing and automation.` + +func NewCmd() *cobra.Command { + list := &cobra.Command{ + Use: "list", + Short: "List contents of an index", + Long: `The list subcommands print the contents of an index. + +` + humanReadabilityOnlyNote, + } + list.AddCommand(newPackagesCmd(), newChannelsCmd(), newBundlesCmd()) + return list +} + +func newPackagesCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "packages ", + Short: "List packages in an index", + Long: `The "channels" command lists the channels from the specified index. + +` + humanReadabilityOnlyNote, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + lp := action.ListPackages{IndexReference: args[0]} + res, err := lp.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} + +func newChannelsCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "channels [packageName]", + Short: "List package channels in an index", + Long: `The "channels" command lists the channels from the specified index and package. + +` + humanReadabilityOnlyNote, + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + lc := action.ListChannels{IndexReference: args[0]} + if len(args) > 1 { + lc.PackageName = args[1] + } + res, err := lc.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} + +func newBundlesCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "bundles ", + Short: "List package bundles in an index", + Long: `The "bundles" command lists the bundles from the specified index and package. +Bundles that exist in multiple channels are duplicated in the output (one +for each channel in which the bundle is present). + +` + humanReadabilityOnlyNote, + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + lb := action.ListBundles{IndexReference: args[0]} + if len(args) > 1 { + lb.PackageName = args[1] + } + res, err := lb.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} diff --git a/staging/operator-registry/internal/action/list.go b/staging/operator-registry/internal/action/list.go new file mode 100644 index 0000000000..972489226b --- /dev/null +++ b/staging/operator-registry/internal/action/list.go @@ -0,0 +1,227 @@ +package action + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "sort" + "strings" + "text/tabwriter" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/internal/declcfg" + "github.com/operator-framework/operator-registry/internal/model" + "github.com/operator-framework/operator-registry/internal/property" +) + +type ListPackages struct { + IndexReference string +} + +func (l *ListPackages) Run(ctx context.Context) (*ListPackagesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs := []model.Package{} + for _, pkg := range m { + pkgs = append(pkgs, *pkg) + } + sort.Slice(pkgs, func(i, j int) bool { + return pkgs[i].Name < pkgs[j].Name + }) + return &ListPackagesResult{Packages: pkgs}, nil +} + +type ListPackagesResult struct { + Packages []model.Package +} + +func (r *ListPackagesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "NAME\tDISPLAY NAME\tDEFAULT CHANNEL"); err != nil { + return err + } + for _, pkg := range r.Packages { + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", pkg.Name, getDisplayName(pkg), pkg.DefaultChannel.Name); err != nil { + return err + } + } + return tw.Flush() +} + +func getDisplayName(pkg model.Package) string { + if pkg.DefaultChannel == nil { + return "" + } + head, err := pkg.DefaultChannel.Head() + if err != nil || head == nil || head.CsvJSON == "" { + return "" + } + + csv := v1alpha1.ClusterServiceVersion{} + if err := json.Unmarshal([]byte(head.CsvJSON), &csv); err != nil { + return "" + } + return csv.Spec.DisplayName +} + +type ListChannels struct { + IndexReference string + PackageName string +} + +func (l *ListChannels) Run(ctx context.Context) (*ListChannelsResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + channels := []model.Channel{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + channels = append(channels, *ch) + } + } + + sort.Slice(channels, func(i, j int) bool { + if channels[i].Package.Name != channels[j].Package.Name { + return channels[i].Package.Name < channels[j].Package.Name + } + return channels[i].Name < channels[j].Name + }) + return &ListChannelsResult{Channels: channels}, nil +} + +type ListChannelsResult struct { + Channels []model.Channel +} + +func (r *ListChannelsResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tHEAD"); err != nil { + return err + } + for _, ch := range r.Channels { + headStr := "" + head, err := ch.Head() + if err != nil { + headStr = fmt.Sprintf("ERROR: %s", err) + } else { + headStr = head.Name + } + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", ch.Package.Name, ch.Name, headStr); err != nil { + return err + } + } + return tw.Flush() +} + +type ListBundles struct { + IndexReference string + PackageName string +} + +func (l *ListBundles) Run(ctx context.Context) (*ListBundlesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + bundles := []model.Bundle{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + bundles = append(bundles, *b) + } + } + } + + sort.Slice(bundles, func(i, j int) bool { + if bundles[i].Package.Name != bundles[j].Package.Name { + return bundles[i].Package.Name < bundles[j].Package.Name + } + if bundles[i].Channel.Name != bundles[j].Channel.Name { + return bundles[i].Channel.Name < bundles[j].Channel.Name + } + return bundles[i].Name < bundles[j].Name + }) + return &ListBundlesResult{Bundles: bundles}, nil +} + +type ListBundlesResult struct { + Bundles []model.Bundle +} + +func (r *ListBundlesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tBUNDLE\tREPLACES\tSKIPS\tSKIP RANGE\tIMAGE"); err != nil { + return err + } + for _, b := range r.Bundles { + skipRange, err := getSkipRange(b) + if err != nil { + return fmt.Errorf("get skipRange for bundle %q: %v", b.Name, err) + } + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", b.Package.Name, b.Channel.Name, b.Name, b.Replaces, strings.Join(b.Skips, ","), skipRange, b.Image); err != nil { + return err + } + + } + return tw.Flush() +} + +func getSkipRange(b model.Bundle) (string, error) { + props, err := property.Parse(b.Properties) + if err != nil { + return "", err + } + if len(props.SkipRanges) > 1 { + return "", fmt.Errorf("multiple skip ranges not supported") + } + if len(props.SkipRanges) == 0 { + return "", nil + } + return string(props.SkipRanges[0]), nil +} + +func indexRefToModel(ctx context.Context, ref string) (model.Model, error) { + render := Render{ + Refs: []string{ref}, + AllowedRefMask: RefDCImage | RefDCDir | RefSqliteImage | RefSqliteFile, + } + cfg, err := render.Run(ctx) + if err != nil { + if errors.Is(err, &ErrNotAllowed{}) { + return nil, fmt.Errorf("cannot list non-index %q", ref) + } + return nil, err + } + + return declcfg.ConvertToModel(*cfg) +} + +func getPackages(m model.Model, packageName string) (model.Model, error) { + if packageName == "" { + return m, nil + } + pkg, ok := m[packageName] + if !ok { + return nil, fmt.Errorf("package %q not found", packageName) + } + return model.Model{packageName: pkg}, nil +} diff --git a/staging/operator-registry/internal/action/list_test.go b/staging/operator-registry/internal/action/list_test.go new file mode 100644 index 0000000000..f1d4a7fcd9 --- /dev/null +++ b/staging/operator-registry/internal/action/list_test.go @@ -0,0 +1,117 @@ +package action + +import ( + "bytes" + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestListPackages(t *testing.T) { + type spec struct { + name string + list ListPackages + expected string + } + + specs := []spec{ + { + name: "Success", + list: ListPackages{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, + expected: `NAME DISPLAY NAME DEFAULT CHANNEL +foo Foo Operator beta +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expected, buf.String()) + }) + } +} + +func TestListChannels(t *testing.T) { + type spec struct { + name string + list ListChannels + expected string + } + specs := []spec{ + { + name: "Success/WithPackage", + list: ListChannels{IndexReference: "testdata/foo-index-v0.2.0-declcfg", PackageName: "foo"}, + expected: `PACKAGE CHANNEL HEAD +foo beta foo.v0.2.0 +foo stable foo.v0.2.0 +`, + }, + { + name: "Success/WithoutPackage", + list: ListChannels{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, + expected: `PACKAGE CHANNEL HEAD +foo beta foo.v0.2.0 +foo stable foo.v0.2.0 +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expected, buf.String()) + }) + } +} + +func TestListBundles(t *testing.T) { + type spec struct { + name string + list ListBundles + expected string + } + specs := []spec{ + { + name: "Success/WithPackage", + list: ListBundles{IndexReference: "testdata/foo-index-v0.2.0-declcfg", PackageName: "foo"}, + expected: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE +foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 +foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +`, + }, + { + name: "Success/WithoutPackage", + list: ListBundles{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, + expected: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE +foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 +foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expected, buf.String()) + }) + } +} diff --git a/staging/operator-registry/internal/action/render.go b/staging/operator-registry/internal/action/render.go index 64393c077a..2f4293a394 100644 --- a/staging/operator-registry/internal/action/render.go +++ b/staging/operator-registry/internal/action/render.go @@ -25,9 +25,34 @@ import ( "github.com/operator-framework/operator-registry/pkg/sqlite" ) +type RefType uint + +const ( + RefBundleImage RefType = 1 << iota + RefSqliteImage + RefSqliteFile + RefDCImage + RefDCDir + + RefAll = 0 +) + +func (r RefType) Allowed(refType RefType) bool { + return r == RefAll || r&refType == refType +} + +var _ error = &ErrNotAllowed{} + +type ErrNotAllowed struct{} + +func (_ *ErrNotAllowed) Error() string { + return "not allowed" +} + type Render struct { - Refs []string - Registry image.Registry + Refs []string + Registry image.Registry + AllowedRefMask RefType } func nullLogger() *logrus.Entry { @@ -48,26 +73,9 @@ func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) { var cfgs []declcfg.DeclarativeConfig for _, ref := range r.Refs { - var ( - cfg *declcfg.DeclarativeConfig - err error - ) - if stat, serr := os.Stat(ref); serr == nil { - if stat.IsDir() { - cfg, err = declcfg.LoadFS(os.DirFS(ref)) - } else { - // The only supported file type is an sqlite DB file, - // since declarative configs will be in a directory. - if err := checkDBFile(ref); err != nil { - return nil, err - } - cfg, err = sqliteToDeclcfg(ctx, ref) - } - } else { - cfg, err = r.imageToDeclcfg(ctx, ref) - } + cfg, err := r.renderReference(ctx, ref) if err != nil { - return nil, fmt.Errorf("render reference %q: %v", ref, err) + return nil, fmt.Errorf("render reference %q: %w", ref, err) } renderBundleObjects(cfg) cfgs = append(cfgs, *cfg) @@ -96,6 +104,28 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) { return reg, nil } +func (r Render) renderReference(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) { + if stat, serr := os.Stat(ref); serr == nil { + if stat.IsDir() { + if !r.AllowedRefMask.Allowed(RefDCDir) { + return nil, fmt.Errorf("cannot render DC directory: %w", &ErrNotAllowed{}) + } + return declcfg.LoadFS(os.DirFS(ref)) + } else { + // The only supported file type is an sqlite DB file, + // since declarative configs will be in a directory. + if err := checkDBFile(ref); err != nil { + return nil, err + } + if !r.AllowedRefMask.Allowed(RefSqliteFile) { + return nil, fmt.Errorf("cannot render sqlite file: %w", &ErrNotAllowed{}) + } + return sqliteToDeclcfg(ctx, ref) + } + } + return r.imageToDeclcfg(ctx, ref) +} + func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.DeclarativeConfig, error) { ref := image.SimpleReference(imageRef) if err := r.Registry.Pull(ctx, ref); err != nil { @@ -116,17 +146,26 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D var cfg *declcfg.DeclarativeConfig if dbFile, ok := labels[containertools.DbLocationLabel]; ok { + if !r.AllowedRefMask.Allowed(RefSqliteImage) { + return nil, fmt.Errorf("cannot render sqlite image: %w", &ErrNotAllowed{}) + } cfg, err = sqliteToDeclcfg(ctx, filepath.Join(tmpDir, dbFile)) if err != nil { return nil, err } } else if configsDir, ok := labels["operators.operatorframework.io.index.configs.v1"]; ok { // TODO(joelanford): Make a constant for above configs location label + if !r.AllowedRefMask.Allowed(RefDCImage) { + return nil, fmt.Errorf("cannot render DC image: %w", &ErrNotAllowed{}) + } cfg, err = declcfg.LoadFS(os.DirFS(filepath.Join(tmpDir, configsDir))) if err != nil { return nil, err } } else if _, ok := labels[bundle.PackageLabel]; ok { + if !r.AllowedRefMask.Allowed(RefBundleImage) { + return nil, fmt.Errorf("cannot render bundle image: %w", &ErrNotAllowed{}) + } img, err := registry.NewImageInput(ref, tmpDir) if err != nil { return nil, err diff --git a/staging/operator-registry/internal/action/render_test.go b/staging/operator-registry/internal/action/render_test.go index b9ed5be32d..f75ae54e91 100644 --- a/staging/operator-registry/internal/action/render_test.go +++ b/staging/operator-registry/internal/action/render_test.go @@ -3,6 +3,7 @@ package action_test import ( "context" "embed" + "errors" "io/fs" "os" "path/filepath" @@ -51,6 +52,14 @@ func TestRender(t *testing.T) { foov2crd, err = yaml.ToJSON(foov2crd) require.NoError(t, err) + dir := t.TempDir() + dbFile := filepath.Join(dir, "index.db") + imageMap := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + } + assert.NoError(t, generateSqliteFile(dbFile, imageMap)) + specs := []spec{ { name: "Success/SqliteIndexImage", @@ -74,6 +83,84 @@ func TestRender(t *testing.T) { Image: "test.registry/foo-operator/foo-bundle:v0.1.0", Properties: []property.Property{ property.MustBuildChannel("beta", ""), + property.MustBuildChannel("stable", ""), + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "v0.1.0"), + property.MustBuildSkipRange("<0.1.0"), + property.MustBuildBundleObjectData(foov1csv), + property.MustBuildBundleObjectData(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildChannel("beta", "foo.v0.1.0"), + property.MustBuildChannel("stable", "foo.v0.1.0"), + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "v0.1.0"), + property.MustBuildSkipRange("<0.2.0"), + property.MustBuildSkips("foo.v0.1.1"), + property.MustBuildSkips("foo.v0.1.2"), + property.MustBuildBundleObjectData(foov2csv), + property.MustBuildBundleObjectData(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/SqliteFile", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildChannel("beta", ""), + property.MustBuildChannel("stable", ""), property.MustBuildGVK("test.foo", "v1", "Foo"), property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), property.MustBuildPackage("foo", "0.1.0"), @@ -101,6 +188,7 @@ func TestRender(t *testing.T) { Image: "test.registry/foo-operator/foo-bundle:v0.2.0", Properties: []property.Property{ property.MustBuildChannel("beta", "foo.v0.1.0"), + property.MustBuildChannel("stable", "foo.v0.1.0"), property.MustBuildGVK("test.foo", "v1", "Foo"), property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), property.MustBuildPackage("foo", "0.2.0"), @@ -176,6 +264,83 @@ func TestRender(t *testing.T) { Image: "test.registry/foo-operator/foo-bundle:v0.2.0", Properties: []property.Property{ property.MustBuildChannel("beta", "foo.v0.1.0"), + property.MustBuildChannel("stable", "foo.v0.1.0"), + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "v0.1.0"), + property.MustBuildSkipRange("<0.2.0"), + property.MustBuildSkips("foo.v0.1.1"), + property.MustBuildSkips("foo.v0.1.2"), + property.MustBuildBundleObjectData(foov2csv), + property.MustBuildBundleObjectData(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/DeclcfgDirectory", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildChannel("beta", ""), + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "v0.1.0"), + property.MustBuildSkipRange("<0.1.0"), + property.MustBuildBundleObjectData(foov1csv), + property.MustBuildBundleObjectData(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildChannel("beta", "foo.v0.1.0"), + property.MustBuildChannel("stable", "foo.v0.1.0"), property.MustBuildGVK("test.foo", "v1", "Foo"), property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), property.MustBuildPackage("foo", "0.2.0"), @@ -217,6 +382,7 @@ func TestRender(t *testing.T) { Image: "test.registry/foo-operator/foo-bundle:v0.2.0", Properties: []property.Property{ property.MustBuildChannel("beta", "foo.v0.1.0"), + property.MustBuildChannel("stable", "foo.v0.1.0"), property.MustBuildGVK("test.foo", "v1", "Foo"), property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), property.MustBuildPackage("foo", "0.2.0"), @@ -247,111 +413,199 @@ func TestRender(t *testing.T) { } } -func TestRenderDBFile(t *testing.T) { +func TestAllowRefMask(t *testing.T) { + type spec struct { + name string + render action.Render + expectErr error + } - foov1csv, err := bundleImageV1.ReadFile("testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml") - require.NoError(t, err) - foov1crd, err := bundleImageV1.ReadFile("testdata/foo-bundle-v0.1.0/manifests/foos.test.foo.crd.yaml") - require.NoError(t, err) - foov2csv, err := bundleImageV2.ReadFile("testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml") - require.NoError(t, err) - foov2crd, err := bundleImageV2.ReadFile("testdata/foo-bundle-v0.2.0/manifests/foos.test.foo.crd.yaml") + reg, err := newRegistry() require.NoError(t, err) - foov1csv, err = yaml.ToJSON(foov1csv) - require.NoError(t, err) - foov1crd, err = yaml.ToJSON(foov1crd) - require.NoError(t, err) - foov2csv, err = yaml.ToJSON(foov2csv) - require.NoError(t, err) - foov2crd, err = yaml.ToJSON(foov2crd) - require.NoError(t, err) + dir := t.TempDir() + dbFile := filepath.Join(dir, "index.db") + imageMap := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + } + assert.NoError(t, generateSqliteFile(dbFile, imageMap)) - expectCfg := &declcfg.DeclarativeConfig{ - Packages: []declcfg.Package{ - { - Schema: "olm.package", - Name: "foo", - DefaultChannel: "beta", + specs := []spec{ + { + name: "SqliteImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefSqliteImage, }, + expectErr: nil, }, - Bundles: []declcfg.Bundle{ - { - Schema: "olm.bundle", - Name: "foo.v0.1.0", - Package: "foo", - Image: "test.registry/foo-operator/foo-bundle:v0.1.0", - Properties: []property.Property{ - property.MustBuildChannel("beta", ""), - property.MustBuildGVK("test.foo", "v1", "Foo"), - property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), - property.MustBuildPackage("foo", "0.1.0"), - property.MustBuildPackageRequired("bar", "v0.1.0"), - property.MustBuildSkipRange("<0.1.0"), - property.MustBuildBundleObjectData(foov1csv), - property.MustBuildBundleObjectData(foov1crd), - }, - RelatedImages: []declcfg.RelatedImage{ - { - Name: "operator", - Image: "test.registry/foo-operator/foo:v0.1.0", - }, - { - Image: "test.registry/foo-operator/foo-bundle:v0.1.0", - }, - }, - CsvJSON: string(foov1csv), - Objects: []string{string(foov1csv), string(foov1crd)}, + { + name: "SqliteImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteFile | action.RefBundleImage, }, - { - Schema: "olm.bundle", - Name: "foo.v0.2.0", - Package: "foo", - Image: "test.registry/foo-operator/foo-bundle:v0.2.0", - Properties: []property.Property{ - property.MustBuildChannel("beta", "foo.v0.1.0"), - property.MustBuildGVK("test.foo", "v1", "Foo"), - property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), - property.MustBuildPackage("foo", "0.2.0"), - property.MustBuildPackageRequired("bar", "v0.1.0"), - property.MustBuildSkipRange("<0.2.0"), - property.MustBuildSkips("foo.v0.1.1"), - property.MustBuildSkips("foo.v0.1.2"), - property.MustBuildBundleObjectData(foov2csv), - property.MustBuildBundleObjectData(foov2crd), - }, - RelatedImages: []declcfg.RelatedImage{ - { - Name: "operator", - Image: "test.registry/foo-operator/foo:v0.2.0", - }, - { - Image: "test.registry/foo-operator/foo-bundle:v0.2.0", - }, + expectErr: &action.ErrNotAllowed{}, + }, + { + name: "SqliteFile/Allowed", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + AllowedRefMask: action.RefSqliteFile, + }, + expectErr: nil, + }, + { + name: "SqliteFile/NotAllowed", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefBundleImage, + }, + expectErr: &action.ErrNotAllowed{}, + }, + { + name: "DeclcfgImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage, + }, + expectErr: nil, + }, + { + name: "DeclcfgImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage, + }, + expectErr: &action.ErrNotAllowed{}, + }, + { + name: "DeclcfgDir/Allowed", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + AllowedRefMask: action.RefDCDir, + }, + expectErr: nil, + }, + { + name: "DeclcfgDir/NotAllowed", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage, + }, + expectErr: &action.ErrNotAllowed{}, + }, + { + name: "BundleImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefBundleImage, + }, + expectErr: nil, + }, + { + name: "BundleImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile, + }, + expectErr: &action.ErrNotAllowed{}, + }, + { + name: "All/Allowed", + render: action.Render{ + Refs: []string{ + "test.registry/foo-operator/foo-index-sqlite:v0.2.0", + dbFile, + "test.registry/foo-operator/foo-index-declcfg:v0.2.0", + "testdata/foo-index-v0.2.0-declcfg", + "test.registry/foo-operator/foo-bundle:v0.2.0", }, - CsvJSON: string(foov2csv), - Objects: []string{string(foov2csv), string(foov2crd)}, + Registry: reg, }, + expectErr: nil, }, } - - dir := t.TempDir() - - dbFile := filepath.Join(dir, "index.db") - imageMap := map[image.Reference]string{ - image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", - image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + _, err := s.render.Run(context.Background()) + require.True(t, errors.Is(err, s.expectErr), "expected error %#v to be %#v", err, s.expectErr) + }) } - assert.NoError(t, generateSqliteFile(dbFile, imageMap)) +} - render := action.Render{ - Refs: []string{dbFile}, - Registry: &image.MockRegistry{RemoteImages: map[image.Reference]*image.MockImage{}}, +func TestAllowRefMaskAllowed(t *testing.T) { + type spec struct { + name string + mask action.RefType + pass []action.RefType + fail []action.RefType + expect bool } - actualCfg, actualErr := render.Run(context.Background()) - assert.NoError(t, actualErr) - assert.Equal(t, expectCfg, actualCfg) + specs := []spec{ + { + name: "Mask/All", + mask: action.RefAll, + pass: []action.RefType{ + action.RefDCImage, + action.RefDCDir, + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + }, + fail: []action.RefType{}, + }, + { + name: "Mask/One", + mask: action.RefDCImage, + pass: []action.RefType{ + action.RefDCImage, + }, + fail: []action.RefType{ + action.RefDCDir, + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + }, + }, + { + name: "Mask/Some", + mask: action.RefDCImage | action.RefDCDir, + pass: []action.RefType{ + action.RefDCImage, + action.RefDCDir, + }, + fail: []action.RefType{ + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + }, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + for _, c := range s.pass { + actual := s.mask.Allowed(c) + require.True(t, actual) + } + for _, c := range s.fail { + actual := s.mask.Allowed(c) + require.False(t, actual) + } + }) + } } //go:embed testdata/foo-bundle-v0.1.0/manifests/* diff --git a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml index 830fb457af..189b6849eb 100644 --- a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml +++ b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml @@ -6,6 +6,7 @@ metadata: annotations: olm.skipRange: <0.1.0 spec: + displayName: "Foo Operator" customresourcedefinitions: owned: - group: test.foo diff --git a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml index 607918ec91..d7e30bee03 100644 --- a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml +++ b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml @@ -6,6 +6,7 @@ metadata: annotations: olm.skipRange: <0.2.0 spec: + displayName: "Foo Operator" customresourcedefinitions: owned: - group: test.foo diff --git a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml index 34187f125f..dc4cc05f68 100644 --- a/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml +++ b/staging/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml @@ -1,4 +1,4 @@ annotations: operators.operatorframework.io.bundle.package.v1: foo - operators.operatorframework.io.bundle.channels.v1: beta + operators.operatorframework.io.bundle.channels.v1: beta,stable operators.operatorframework.io.bundle.channel.default.v1: beta diff --git a/staging/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml b/staging/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml index da0b2131e5..2e108e380d 100644 --- a/staging/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml +++ b/staging/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml @@ -33,7 +33,7 @@ properties: value: <0.1.0 - type: olm.bundle.object value: - data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjEuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwidmVyc2lvbiI6IjAuMS4wIn19 + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= - type: olm.bundle.object value: data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 @@ -51,6 +51,10 @@ properties: value: name: beta replaces: foo.v0.1.0 + - type: olm.channel + value: + name: stable + replaces: foo.v0.1.0 - type: olm.gvk value: group: test.foo @@ -77,7 +81,7 @@ properties: value: foo.v0.1.2 - type: olm.bundle.object value: - data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4xLjAiLCJza2lwcyI6WyJmb28udjAuMS4xIiwiZm9vLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= - type: olm.bundle.object value: data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 diff --git a/staging/operator-registry/internal/declcfg/helpers_test.go b/staging/operator-registry/internal/declcfg/helpers_test.go index d41fc99f75..748692a42a 100644 --- a/staging/operator-registry/internal/declcfg/helpers_test.go +++ b/staging/operator-registry/internal/declcfg/helpers_test.go @@ -125,6 +125,12 @@ func newTestBundle(packageName, version string, opts ...bundleOpt) Bundle { for _, opt := range opts { opt(&b) } + sort.Slice(b.Properties, func(i, j int) bool { + if b.Properties[i].Type != b.Properties[j].Type { + return b.Properties[i].Type < b.Properties[j].Type + } + return string(b.Properties[i].Value) < string(b.Properties[j].Value) + }) return b } diff --git a/staging/operator-registry/internal/declcfg/model_to_declcfg.go b/staging/operator-registry/internal/declcfg/model_to_declcfg.go index d3d4ed686d..df8357a917 100644 --- a/staging/operator-registry/internal/declcfg/model_to_declcfg.go +++ b/staging/operator-registry/internal/declcfg/model_to_declcfg.go @@ -68,6 +68,14 @@ func traverseModelChannels(mpkg model.Package) []Bundle { var out []Bundle for _, b := range bundles { b.Properties = property.Deduplicate(b.Properties) + + sort.Slice(b.Properties, func(i, j int) bool { + if b.Properties[i].Type != b.Properties[j].Type { + return b.Properties[i].Type < b.Properties[j].Type + } + return string(b.Properties[i].Value) < string(b.Properties[j].Value) + }) + out = append(out, *b) } return out diff --git a/staging/operator-registry/internal/declcfg/write_test.go b/staging/operator-registry/internal/declcfg/write_test.go index e48c139efd..4b69bc5b05 100644 --- a/staging/operator-registry/internal/declcfg/write_test.go +++ b/staging/operator-registry/internal/declcfg/write_test.go @@ -35,10 +35,9 @@ func TestWriteJSON(t *testing.T) { "image": "anakin-bundle:v0.0.1", "properties": [ { - "type": "olm.package", + "type": "olm.bundle.object", "value": { - "packageName": "anakin", - "version": "0.0.1" + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" } }, { @@ -48,9 +47,9 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.bundle.object", + "type": "olm.channel", "value": { - "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + "name": "dark" } }, { @@ -60,9 +59,10 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.channel", + "type": "olm.package", "value": { - "name": "dark" + "packageName": "anakin", + "version": "0.0.1" } } ], @@ -80,10 +80,9 @@ func TestWriteJSON(t *testing.T) { "image": "anakin-bundle:v0.1.0", "properties": [ { - "type": "olm.package", + "type": "olm.bundle.object", "value": { - "packageName": "anakin", - "version": "0.1.0" + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" } }, { @@ -93,9 +92,10 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.bundle.object", + "type": "olm.channel", "value": { - "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + "name": "dark", + "replaces": "anakin.v0.0.1" } }, { @@ -106,10 +106,10 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.channel", + "type": "olm.package", "value": { - "name": "dark", - "replaces": "anakin.v0.0.1" + "packageName": "anakin", + "version": "0.1.0" } } ], @@ -127,10 +127,9 @@ func TestWriteJSON(t *testing.T) { "image": "anakin-bundle:v0.1.1", "properties": [ { - "type": "olm.package", + "type": "olm.bundle.object", "value": { - "packageName": "anakin", - "version": "0.1.1" + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" } }, { @@ -140,16 +139,17 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.bundle.object", + "type": "olm.channel", "value": { - "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + "name": "dark", + "replaces": "anakin.v0.0.1" } }, { - "type": "olm.channel", + "type": "olm.package", "value": { - "name": "dark", - "replaces": "anakin.v0.0.1" + "packageName": "anakin", + "version": "0.1.1" } }, { @@ -186,10 +186,9 @@ func TestWriteJSON(t *testing.T) { "image": "boba-fett-bundle:v1.0.0", "properties": [ { - "type": "olm.package", + "type": "olm.bundle.object", "value": { - "packageName": "boba-fett", - "version": "1.0.0" + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" } }, { @@ -199,15 +198,16 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.bundle.object", + "type": "olm.channel", "value": { - "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + "name": "mando" } }, { - "type": "olm.channel", + "type": "olm.package", "value": { - "name": "mando" + "packageName": "boba-fett", + "version": "1.0.0" } } ], @@ -225,10 +225,9 @@ func TestWriteJSON(t *testing.T) { "image": "boba-fett-bundle:v2.0.0", "properties": [ { - "type": "olm.package", + "type": "olm.bundle.object", "value": { - "packageName": "boba-fett", - "version": "2.0.0" + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" } }, { @@ -238,16 +237,17 @@ func TestWriteJSON(t *testing.T) { } }, { - "type": "olm.bundle.object", + "type": "olm.channel", "value": { - "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + "name": "mando", + "replaces": "boba-fett.v1.0.0" } }, { - "type": "olm.channel", + "type": "olm.package", "value": { - "name": "mando", - "replaces": "boba-fett.v1.0.0" + "packageName": "boba-fett", + "version": "2.0.0" } } ], @@ -305,22 +305,22 @@ image: anakin-bundle:v0.0.1 name: anakin.v0.0.1 package: anakin properties: -- type: olm.package +- type: olm.bundle.object value: - packageName: anakin - version: 0.0.1 + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= - type: olm.bundle.object value: ref: objects/anakin.v0.0.1.csv.yaml -- type: olm.bundle.object +- type: olm.channel value: - data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= + name: dark - type: olm.channel value: name: light -- type: olm.channel +- type: olm.package value: - name: dark + packageName: anakin + version: 0.0.1 relatedImages: - image: anakin-bundle:v0.0.1 name: bundle @@ -330,24 +330,24 @@ image: anakin-bundle:v0.1.0 name: anakin.v0.1.0 package: anakin properties: -- type: olm.package - value: - packageName: anakin - version: 0.1.0 - type: olm.bundle.object value: - ref: objects/anakin.v0.1.0.csv.yaml + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= - type: olm.bundle.object value: - data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= + ref: objects/anakin.v0.1.0.csv.yaml - type: olm.channel value: - name: light + name: dark replaces: anakin.v0.0.1 - type: olm.channel value: - name: dark + name: light replaces: anakin.v0.0.1 +- type: olm.package + value: + packageName: anakin + version: 0.1.0 relatedImages: - image: anakin-bundle:v0.1.0 name: bundle @@ -357,20 +357,20 @@ image: anakin-bundle:v0.1.1 name: anakin.v0.1.1 package: anakin properties: -- type: olm.package - value: - packageName: anakin - version: 0.1.1 - type: olm.bundle.object value: - ref: objects/anakin.v0.1.1.csv.yaml + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= - type: olm.bundle.object value: - data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= + ref: objects/anakin.v0.1.1.csv.yaml - type: olm.channel value: name: dark replaces: anakin.v0.0.1 +- type: olm.package + value: + packageName: anakin + version: 0.1.1 - type: olm.skips value: anakin.v0.1.0 relatedImages: @@ -394,19 +394,19 @@ image: boba-fett-bundle:v1.0.0 name: boba-fett.v1.0.0 package: boba-fett properties: -- type: olm.package - value: - packageName: boba-fett - version: 1.0.0 - type: olm.bundle.object value: - ref: objects/boba-fett.v1.0.0.csv.yaml + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= - type: olm.bundle.object value: - data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= + ref: objects/boba-fett.v1.0.0.csv.yaml - type: olm.channel value: name: mando +- type: olm.package + value: + packageName: boba-fett + version: 1.0.0 relatedImages: - image: boba-fett-bundle:v1.0.0 name: bundle @@ -416,20 +416,20 @@ image: boba-fett-bundle:v2.0.0 name: boba-fett.v2.0.0 package: boba-fett properties: -- type: olm.package - value: - packageName: boba-fett - version: 2.0.0 - type: olm.bundle.object value: - ref: objects/boba-fett.v2.0.0.csv.yaml + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= - type: olm.bundle.object value: - data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= + ref: objects/boba-fett.v2.0.0.csv.yaml - type: olm.channel value: name: mando replaces: boba-fett.v1.0.0 +- type: olm.package + value: + packageName: boba-fett + version: 2.0.0 relatedImages: - image: boba-fett-bundle:v2.0.0 name: bundle diff --git a/staging/operator-registry/internal/model/model.go b/staging/operator-registry/internal/model/model.go index 330ea84db1..78639d93d0 100644 --- a/staging/operator-registry/internal/model/model.go +++ b/staging/operator-registry/internal/model/model.go @@ -3,6 +3,7 @@ package model import ( "errors" "fmt" + "sort" "strings" "github.com/h2non/filetype" @@ -160,6 +161,7 @@ func (c Channel) Head() (*Bundle, error) { for _, head := range heads { headNames = append(headNames, head.Name) } + sort.Strings(headNames) return nil, fmt.Errorf("multiple channel heads found in graph: %s", strings.Join(headNames, ", ")) } return heads[0], nil diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go index 323a19f817..42e50e3ddf 100644 --- a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go +++ b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/cmd.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle" + "github.com/operator-framework/operator-registry/cmd/opm/alpha/list" ) func NewCmd() *cobra.Command { @@ -13,6 +14,6 @@ func NewCmd() *cobra.Command { Short: "Run an alpha subcommand", } - runCmd.AddCommand(bundle.NewCmd()) + runCmd.AddCommand(bundle.NewCmd(), list.NewCmd()) return runCmd } diff --git a/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/list/cmd.go b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/list/cmd.go new file mode 100644 index 0000000000..8309b089a1 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/list/cmd.go @@ -0,0 +1,107 @@ +package list + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "github.com/operator-framework/operator-registry/internal/action" +) + +const humanReadabilityOnlyNote = `NOTE: This is meant to be used for convenience and human-readability only. The +CLI and output format are subject to change, so it is not recommended to depend +on the output in any programs or scripts. Use the "render" subcommand to do +more complex processing and automation.` + +func NewCmd() *cobra.Command { + list := &cobra.Command{ + Use: "list", + Short: "List contents of an index", + Long: `The list subcommands print the contents of an index. + +` + humanReadabilityOnlyNote, + } + list.AddCommand(newPackagesCmd(), newChannelsCmd(), newBundlesCmd()) + return list +} + +func newPackagesCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "packages ", + Short: "List packages in an index", + Long: `The "channels" command lists the channels from the specified index. + +` + humanReadabilityOnlyNote, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + lp := action.ListPackages{IndexReference: args[0]} + res, err := lp.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} + +func newChannelsCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "channels [packageName]", + Short: "List package channels in an index", + Long: `The "channels" command lists the channels from the specified index and package. + +` + humanReadabilityOnlyNote, + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + lc := action.ListChannels{IndexReference: args[0]} + if len(args) > 1 { + lc.PackageName = args[1] + } + res, err := lc.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} + +func newBundlesCmd() *cobra.Command { + logger := logrus.New() + + return &cobra.Command{ + Use: "bundles ", + Short: "List package bundles in an index", + Long: `The "bundles" command lists the bundles from the specified index and package. +Bundles that exist in multiple channels are duplicated in the output (one +for each channel in which the bundle is present). + +` + humanReadabilityOnlyNote, + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + lb := action.ListBundles{IndexReference: args[0]} + if len(args) > 1 { + lb.PackageName = args[1] + } + res, err := lb.Run(cmd.Context()) + if err != nil { + logger.Fatal(err) + } + if err := res.WriteColumns(os.Stdout); err != nil { + logger.Fatal(err) + } + return nil + }, + } +} diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/list.go b/vendor/github.com/operator-framework/operator-registry/internal/action/list.go new file mode 100644 index 0000000000..972489226b --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/list.go @@ -0,0 +1,227 @@ +package action + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "sort" + "strings" + "text/tabwriter" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/internal/declcfg" + "github.com/operator-framework/operator-registry/internal/model" + "github.com/operator-framework/operator-registry/internal/property" +) + +type ListPackages struct { + IndexReference string +} + +func (l *ListPackages) Run(ctx context.Context) (*ListPackagesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs := []model.Package{} + for _, pkg := range m { + pkgs = append(pkgs, *pkg) + } + sort.Slice(pkgs, func(i, j int) bool { + return pkgs[i].Name < pkgs[j].Name + }) + return &ListPackagesResult{Packages: pkgs}, nil +} + +type ListPackagesResult struct { + Packages []model.Package +} + +func (r *ListPackagesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "NAME\tDISPLAY NAME\tDEFAULT CHANNEL"); err != nil { + return err + } + for _, pkg := range r.Packages { + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", pkg.Name, getDisplayName(pkg), pkg.DefaultChannel.Name); err != nil { + return err + } + } + return tw.Flush() +} + +func getDisplayName(pkg model.Package) string { + if pkg.DefaultChannel == nil { + return "" + } + head, err := pkg.DefaultChannel.Head() + if err != nil || head == nil || head.CsvJSON == "" { + return "" + } + + csv := v1alpha1.ClusterServiceVersion{} + if err := json.Unmarshal([]byte(head.CsvJSON), &csv); err != nil { + return "" + } + return csv.Spec.DisplayName +} + +type ListChannels struct { + IndexReference string + PackageName string +} + +func (l *ListChannels) Run(ctx context.Context) (*ListChannelsResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + channels := []model.Channel{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + channels = append(channels, *ch) + } + } + + sort.Slice(channels, func(i, j int) bool { + if channels[i].Package.Name != channels[j].Package.Name { + return channels[i].Package.Name < channels[j].Package.Name + } + return channels[i].Name < channels[j].Name + }) + return &ListChannelsResult{Channels: channels}, nil +} + +type ListChannelsResult struct { + Channels []model.Channel +} + +func (r *ListChannelsResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tHEAD"); err != nil { + return err + } + for _, ch := range r.Channels { + headStr := "" + head, err := ch.Head() + if err != nil { + headStr = fmt.Sprintf("ERROR: %s", err) + } else { + headStr = head.Name + } + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", ch.Package.Name, ch.Name, headStr); err != nil { + return err + } + } + return tw.Flush() +} + +type ListBundles struct { + IndexReference string + PackageName string +} + +func (l *ListBundles) Run(ctx context.Context) (*ListBundlesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + bundles := []model.Bundle{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + bundles = append(bundles, *b) + } + } + } + + sort.Slice(bundles, func(i, j int) bool { + if bundles[i].Package.Name != bundles[j].Package.Name { + return bundles[i].Package.Name < bundles[j].Package.Name + } + if bundles[i].Channel.Name != bundles[j].Channel.Name { + return bundles[i].Channel.Name < bundles[j].Channel.Name + } + return bundles[i].Name < bundles[j].Name + }) + return &ListBundlesResult{Bundles: bundles}, nil +} + +type ListBundlesResult struct { + Bundles []model.Bundle +} + +func (r *ListBundlesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tBUNDLE\tREPLACES\tSKIPS\tSKIP RANGE\tIMAGE"); err != nil { + return err + } + for _, b := range r.Bundles { + skipRange, err := getSkipRange(b) + if err != nil { + return fmt.Errorf("get skipRange for bundle %q: %v", b.Name, err) + } + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", b.Package.Name, b.Channel.Name, b.Name, b.Replaces, strings.Join(b.Skips, ","), skipRange, b.Image); err != nil { + return err + } + + } + return tw.Flush() +} + +func getSkipRange(b model.Bundle) (string, error) { + props, err := property.Parse(b.Properties) + if err != nil { + return "", err + } + if len(props.SkipRanges) > 1 { + return "", fmt.Errorf("multiple skip ranges not supported") + } + if len(props.SkipRanges) == 0 { + return "", nil + } + return string(props.SkipRanges[0]), nil +} + +func indexRefToModel(ctx context.Context, ref string) (model.Model, error) { + render := Render{ + Refs: []string{ref}, + AllowedRefMask: RefDCImage | RefDCDir | RefSqliteImage | RefSqliteFile, + } + cfg, err := render.Run(ctx) + if err != nil { + if errors.Is(err, &ErrNotAllowed{}) { + return nil, fmt.Errorf("cannot list non-index %q", ref) + } + return nil, err + } + + return declcfg.ConvertToModel(*cfg) +} + +func getPackages(m model.Model, packageName string) (model.Model, error) { + if packageName == "" { + return m, nil + } + pkg, ok := m[packageName] + if !ok { + return nil, fmt.Errorf("package %q not found", packageName) + } + return model.Model{packageName: pkg}, nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/render.go b/vendor/github.com/operator-framework/operator-registry/internal/action/render.go index 64393c077a..2f4293a394 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/action/render.go +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/render.go @@ -25,9 +25,34 @@ import ( "github.com/operator-framework/operator-registry/pkg/sqlite" ) +type RefType uint + +const ( + RefBundleImage RefType = 1 << iota + RefSqliteImage + RefSqliteFile + RefDCImage + RefDCDir + + RefAll = 0 +) + +func (r RefType) Allowed(refType RefType) bool { + return r == RefAll || r&refType == refType +} + +var _ error = &ErrNotAllowed{} + +type ErrNotAllowed struct{} + +func (_ *ErrNotAllowed) Error() string { + return "not allowed" +} + type Render struct { - Refs []string - Registry image.Registry + Refs []string + Registry image.Registry + AllowedRefMask RefType } func nullLogger() *logrus.Entry { @@ -48,26 +73,9 @@ func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) { var cfgs []declcfg.DeclarativeConfig for _, ref := range r.Refs { - var ( - cfg *declcfg.DeclarativeConfig - err error - ) - if stat, serr := os.Stat(ref); serr == nil { - if stat.IsDir() { - cfg, err = declcfg.LoadFS(os.DirFS(ref)) - } else { - // The only supported file type is an sqlite DB file, - // since declarative configs will be in a directory. - if err := checkDBFile(ref); err != nil { - return nil, err - } - cfg, err = sqliteToDeclcfg(ctx, ref) - } - } else { - cfg, err = r.imageToDeclcfg(ctx, ref) - } + cfg, err := r.renderReference(ctx, ref) if err != nil { - return nil, fmt.Errorf("render reference %q: %v", ref, err) + return nil, fmt.Errorf("render reference %q: %w", ref, err) } renderBundleObjects(cfg) cfgs = append(cfgs, *cfg) @@ -96,6 +104,28 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) { return reg, nil } +func (r Render) renderReference(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) { + if stat, serr := os.Stat(ref); serr == nil { + if stat.IsDir() { + if !r.AllowedRefMask.Allowed(RefDCDir) { + return nil, fmt.Errorf("cannot render DC directory: %w", &ErrNotAllowed{}) + } + return declcfg.LoadFS(os.DirFS(ref)) + } else { + // The only supported file type is an sqlite DB file, + // since declarative configs will be in a directory. + if err := checkDBFile(ref); err != nil { + return nil, err + } + if !r.AllowedRefMask.Allowed(RefSqliteFile) { + return nil, fmt.Errorf("cannot render sqlite file: %w", &ErrNotAllowed{}) + } + return sqliteToDeclcfg(ctx, ref) + } + } + return r.imageToDeclcfg(ctx, ref) +} + func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.DeclarativeConfig, error) { ref := image.SimpleReference(imageRef) if err := r.Registry.Pull(ctx, ref); err != nil { @@ -116,17 +146,26 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D var cfg *declcfg.DeclarativeConfig if dbFile, ok := labels[containertools.DbLocationLabel]; ok { + if !r.AllowedRefMask.Allowed(RefSqliteImage) { + return nil, fmt.Errorf("cannot render sqlite image: %w", &ErrNotAllowed{}) + } cfg, err = sqliteToDeclcfg(ctx, filepath.Join(tmpDir, dbFile)) if err != nil { return nil, err } } else if configsDir, ok := labels["operators.operatorframework.io.index.configs.v1"]; ok { // TODO(joelanford): Make a constant for above configs location label + if !r.AllowedRefMask.Allowed(RefDCImage) { + return nil, fmt.Errorf("cannot render DC image: %w", &ErrNotAllowed{}) + } cfg, err = declcfg.LoadFS(os.DirFS(filepath.Join(tmpDir, configsDir))) if err != nil { return nil, err } } else if _, ok := labels[bundle.PackageLabel]; ok { + if !r.AllowedRefMask.Allowed(RefBundleImage) { + return nil, fmt.Errorf("cannot render bundle image: %w", &ErrNotAllowed{}) + } img, err := registry.NewImageInput(ref, tmpDir) if err != nil { return nil, err diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml index 830fb457af..189b6849eb 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml @@ -6,6 +6,7 @@ metadata: annotations: olm.skipRange: <0.1.0 spec: + displayName: "Foo Operator" customresourcedefinitions: owned: - group: test.foo diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml index 607918ec91..d7e30bee03 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml @@ -6,6 +6,7 @@ metadata: annotations: olm.skipRange: <0.2.0 spec: + displayName: "Foo Operator" customresourcedefinitions: owned: - group: test.foo diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml index 34187f125f..dc4cc05f68 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml @@ -1,4 +1,4 @@ annotations: operators.operatorframework.io.bundle.package.v1: foo - operators.operatorframework.io.bundle.channels.v1: beta + operators.operatorframework.io.bundle.channels.v1: beta,stable operators.operatorframework.io.bundle.channel.default.v1: beta diff --git a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml index da0b2131e5..2e108e380d 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml +++ b/vendor/github.com/operator-framework/operator-registry/internal/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml @@ -33,7 +33,7 @@ properties: value: <0.1.0 - type: olm.bundle.object value: - data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjEuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwidmVyc2lvbiI6IjAuMS4wIn19 + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= - type: olm.bundle.object value: data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 @@ -51,6 +51,10 @@ properties: value: name: beta replaces: foo.v0.1.0 + - type: olm.channel + value: + name: stable + replaces: foo.v0.1.0 - type: olm.gvk value: group: test.foo @@ -77,7 +81,7 @@ properties: value: foo.v0.1.2 - type: olm.bundle.object value: - data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4xLjAiLCJza2lwcyI6WyJmb28udjAuMS4xIiwiZm9vLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= - type: olm.bundle.object value: data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 diff --git a/vendor/github.com/operator-framework/operator-registry/internal/declcfg/model_to_declcfg.go b/vendor/github.com/operator-framework/operator-registry/internal/declcfg/model_to_declcfg.go index d3d4ed686d..df8357a917 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/declcfg/model_to_declcfg.go +++ b/vendor/github.com/operator-framework/operator-registry/internal/declcfg/model_to_declcfg.go @@ -68,6 +68,14 @@ func traverseModelChannels(mpkg model.Package) []Bundle { var out []Bundle for _, b := range bundles { b.Properties = property.Deduplicate(b.Properties) + + sort.Slice(b.Properties, func(i, j int) bool { + if b.Properties[i].Type != b.Properties[j].Type { + return b.Properties[i].Type < b.Properties[j].Type + } + return string(b.Properties[i].Value) < string(b.Properties[j].Value) + }) + out = append(out, *b) } return out diff --git a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go b/vendor/github.com/operator-framework/operator-registry/internal/model/model.go index 330ea84db1..78639d93d0 100644 --- a/vendor/github.com/operator-framework/operator-registry/internal/model/model.go +++ b/vendor/github.com/operator-framework/operator-registry/internal/model/model.go @@ -3,6 +3,7 @@ package model import ( "errors" "fmt" + "sort" "strings" "github.com/h2non/filetype" @@ -160,6 +161,7 @@ func (c Channel) Head() (*Bundle, error) { for _, head := range heads { headNames = append(headNames, head.Name) } + sort.Strings(headNames) return nil, fmt.Errorf("multiple channel heads found in graph: %s", strings.Join(headNames, ", ")) } return heads[0], nil diff --git a/vendor/modules.txt b/vendor/modules.txt index 2e97874d94..dab38fd19b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -580,6 +580,7 @@ github.com/operator-framework/operator-registry/cmd/initializer github.com/operator-framework/operator-registry/cmd/opm github.com/operator-framework/operator-registry/cmd/opm/alpha github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle +github.com/operator-framework/operator-registry/cmd/opm/alpha/list github.com/operator-framework/operator-registry/cmd/opm/index github.com/operator-framework/operator-registry/cmd/opm/init github.com/operator-framework/operator-registry/cmd/opm/registry From 0a118aa9200347cb4ebdc18e032e1f9e0425d5bc Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Mon, 19 Jul 2021 11:17:48 -0400 Subject: [PATCH 19/30] improve tests Signed-off-by: Joe Lanford Upstream-repository: operator-registry Upstream-commit: c6eae74a1bdec836b5c4ca6b225389e199166c98 --- .../internal/action/list_test.go | 119 ++++++++++++------ .../action/testdata/list-index/bar/index.yaml | 91 ++++++++++++++ .../action/testdata/list-index/foo/index.yaml | 91 ++++++++++++++ 3 files changed, 266 insertions(+), 35 deletions(-) create mode 100644 staging/operator-registry/internal/action/testdata/list-index/bar/index.yaml create mode 100644 staging/operator-registry/internal/action/testdata/list-index/foo/index.yaml diff --git a/staging/operator-registry/internal/action/list_test.go b/staging/operator-registry/internal/action/list_test.go index f1d4a7fcd9..87f53886e0 100644 --- a/staging/operator-registry/internal/action/list_test.go +++ b/staging/operator-registry/internal/action/list_test.go @@ -10,83 +10,114 @@ import ( func TestListPackages(t *testing.T) { type spec struct { - name string - list ListPackages - expected string + name string + list ListPackages + expectedOut string + expectedErr string } specs := []spec{ { - name: "Success", - list: ListPackages{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, - expected: `NAME DISPLAY NAME DEFAULT CHANNEL + name: "Success/ValidIndex", + list: ListPackages{IndexReference: "testdata/list-index"}, + expectedOut: `NAME DISPLAY NAME DEFAULT CHANNEL +bar Bar Operator beta foo Foo Operator beta `, }, + { + name: "Error/UnknownIndex", + list: ListPackages{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": error resolving name : object required`, + }, } for _, s := range specs { t.Run(s.name, func(t *testing.T) { res, err := s.list.Run(context.Background()) - require.NoError(t, err) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) - buf := &bytes.Buffer{} - err = res.WriteColumns(buf) - require.NoError(t, err) + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) - require.Equal(t, s.expected, buf.String()) + require.Equal(t, s.expectedOut, buf.String()) + } }) } } func TestListChannels(t *testing.T) { type spec struct { - name string - list ListChannels - expected string + name string + list ListChannels + expectedOut string + expectedErr string } specs := []spec{ { name: "Success/WithPackage", - list: ListChannels{IndexReference: "testdata/foo-index-v0.2.0-declcfg", PackageName: "foo"}, - expected: `PACKAGE CHANNEL HEAD + list: ListChannels{IndexReference: "testdata/list-index", PackageName: "foo"}, + expectedOut: `PACKAGE CHANNEL HEAD foo beta foo.v0.2.0 foo stable foo.v0.2.0 `, }, { name: "Success/WithoutPackage", - list: ListChannels{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, - expected: `PACKAGE CHANNEL HEAD + list: ListChannels{IndexReference: "testdata/list-index"}, + expectedOut: `PACKAGE CHANNEL HEAD +bar beta bar.v0.2.0 +bar stable bar.v0.2.0 foo beta foo.v0.2.0 foo stable foo.v0.2.0 `, }, + { + name: "Error/UnknownIndex", + list: ListChannels{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": error resolving name : object required`, + }, + { + name: "Error/UnknownPackage", + list: ListChannels{IndexReference: "testdata/list-index", PackageName: "unknown"}, + expectedErr: `package "unknown" not found`, + }, } for _, s := range specs { t.Run(s.name, func(t *testing.T) { res, err := s.list.Run(context.Background()) - require.NoError(t, err) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) - buf := &bytes.Buffer{} - err = res.WriteColumns(buf) - require.NoError(t, err) + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) - require.Equal(t, s.expected, buf.String()) + require.Equal(t, s.expectedOut, buf.String()) + } }) } } func TestListBundles(t *testing.T) { type spec struct { - name string - list ListBundles - expected string + name string + list ListBundles + expectedOut string + expectedErr string } specs := []spec{ { name: "Success/WithPackage", - list: ListBundles{IndexReference: "testdata/foo-index-v0.2.0-declcfg", PackageName: "foo"}, - expected: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE + list: ListBundles{IndexReference: "testdata/list-index", PackageName: "foo"}, + expectedOut: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 @@ -94,24 +125,42 @@ foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 tes }, { name: "Success/WithoutPackage", - list: ListBundles{IndexReference: "testdata/foo-index-v0.2.0-declcfg"}, - expected: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE + list: ListBundles{IndexReference: "testdata/list-index"}, + expectedOut: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE +bar beta bar.v0.1.0 <0.1.0 test.registry/bar-operator/bar-bundle:v0.1.0 +bar beta bar.v0.2.0 bar.v0.1.0 bar.v0.1.1,bar.v0.1.2 <0.2.0 test.registry/bar-operator/bar-bundle:v0.2.0 +bar stable bar.v0.2.0 bar.v0.1.0 bar.v0.1.1,bar.v0.1.2 <0.2.0 test.registry/bar-operator/bar-bundle:v0.2.0 foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 `, }, + { + name: "Error/UnknownIndex", + list: ListBundles{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": error resolving name : object required`, + }, + { + name: "Error/UnknownPackage", + list: ListBundles{IndexReference: "testdata/list-index", PackageName: "unknown"}, + expectedErr: `package "unknown" not found`, + }, } for _, s := range specs { t.Run(s.name, func(t *testing.T) { res, err := s.list.Run(context.Background()) - require.NoError(t, err) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) - buf := &bytes.Buffer{} - err = res.WriteColumns(buf) - require.NoError(t, err) + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) - require.Equal(t, s.expected, buf.String()) + require.Equal(t, s.expectedOut, buf.String()) + } }) } } diff --git a/staging/operator-registry/internal/action/testdata/list-index/bar/index.yaml b/staging/operator-registry/internal/action/testdata/list-index/bar/index.yaml new file mode 100644 index 0000000000..0d2a3610d7 --- /dev/null +++ b/staging/operator-registry/internal/action/testdata/list-index/bar/index.yaml @@ -0,0 +1,91 @@ +--- +schema: olm.package +name: bar +defaultChannel: beta +--- +schema: olm.bundle +package: bar +name: bar.v0.1.0 +image: test.registry/bar-operator/bar-bundle:v0.1.0 +properties: + - type: olm.channel + value: + name: beta + - type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 + - type: olm.gvk.required + value: + group: test.baz + kind: Baz + version: v1alpha1 + - type: olm.package + value: + packageName: bar + version: 0.1.0 + - type: olm.package.required + value: + packageName: baz + versionRange: v0.1.0 + - type: olm.skipRange + value: <0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJiYXIudjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiQmFyIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/bar-operator/bar:v0.1.0 + name: operator + - image: test.registry/bar-operator/bar-bundle:v0.1.0 +--- +schema: olm.bundle +package: bar +name: bar.v0.2.0 +image: test.registry/bar-operator/bar-bundle:v0.2.0 +properties: + - type: olm.channel + value: + name: beta + replaces: bar.v0.1.0 + - type: olm.channel + value: + name: stable + replaces: bar.v0.1.0 + - type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 + - type: olm.gvk.required + value: + group: test.baz + kind: Baz + version: v1alpha1 + - type: olm.package + value: + packageName: bar + version: 0.2.0 + - type: olm.package.required + value: + packageName: baz + versionRange: v0.1.0 + - type: olm.skipRange + value: <0.2.0 + - type: olm.skips + value: bar.v0.1.1 + - type: olm.skips + value: bar.v0.1.2 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiQmFyIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4xLjAiLCJza2lwcyI6WyJiYXIudjAuMS4xIiwiYmFyLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/bar-operator/bar:v0.2.0 + name: operator + - image: test.registry/bar-operator/bar-bundle:v0.2.0 diff --git a/staging/operator-registry/internal/action/testdata/list-index/foo/index.yaml b/staging/operator-registry/internal/action/testdata/list-index/foo/index.yaml new file mode 100644 index 0000000000..2e108e380d --- /dev/null +++ b/staging/operator-registry/internal/action/testdata/list-index/foo/index.yaml @@ -0,0 +1,91 @@ +--- +schema: olm.package +name: foo +defaultChannel: beta +--- +schema: olm.bundle +package: foo +name: foo.v0.1.0 +image: test.registry/foo-operator/foo-bundle:v0.1.0 +properties: + - type: olm.channel + value: + name: beta + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.1.0 + - type: olm.package.required + value: + packageName: bar + versionRange: v0.1.0 + - type: olm.skipRange + value: <0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo:v0.1.0 + name: operator + - image: test.registry/foo-operator/foo-bundle:v0.1.0 +--- +schema: olm.bundle +package: foo +name: foo.v0.2.0 +image: test.registry/foo-operator/foo-bundle:v0.2.0 +properties: + - type: olm.channel + value: + name: beta + replaces: foo.v0.1.0 + - type: olm.channel + value: + name: stable + replaces: foo.v0.1.0 + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.2.0 + - type: olm.package.required + value: + packageName: bar + versionRange: v0.1.0 + - type: olm.skipRange + value: <0.2.0 + - type: olm.skips + value: foo.v0.1.1 + - type: olm.skips + value: foo.v0.1.2 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4xLjAiLCJza2lwcyI6WyJmb28udjAuMS4xIiwiZm9vLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo:v0.2.0 + name: operator + - image: test.registry/foo-operator/foo-bundle:v0.2.0 From 62bd80fe3e6ceeeb0925fe065cfa35c4a9a4b8c8 Mon Sep 17 00:00:00 2001 From: Alexander Greene Date: Mon, 19 Jul 2021 12:11:48 -0400 Subject: [PATCH 20/30] Update extractMessage func Whe building the subscription condition message, check if the status of the InstallPlan is available before iterating through bundle lookup conditions. Also update string returned to include spaces between multiple messages. Signed-off-by: Alexander Greene Upstream-repository: operator-lifecycle-manager Upstream-commit: 804875c45c6337d95313f7e4a68982c77e30f614 --- .../operators/catalog/subscription/state.go | 27 ++++---- .../catalog/subscription/state_test.go | 69 +++++++++++++++++++ .../operators/catalog/subscription/state.go | 27 ++++---- 3 files changed, 95 insertions(+), 28 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go index e7280e39b2..024cb3dd96 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go @@ -511,23 +511,22 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl } func extractMessage(status *v1alpha1.InstallPlanStatus) string { - str := "" - if len(status.BundleLookups) > 0 { - var b bytes.Buffer - for _, lookup := range status.BundleLookups { - if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown { - b.WriteString(cond.Message) - b.WriteString(".") - } - } - str = b.String() + if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown && cond.Message != "" { + return cond.Message } - if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown { - if cond.Message != "" { - str = cond.Message + + var b bytes.Buffer + for _, lookup := range status.BundleLookups { + if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown && cond.Message != "" { + if b.Len() != 0 { + b.WriteString(" ") + } + b.WriteString(cond.Message) + b.WriteString(".") } } - return str + + return b.String() } type installPlanKnownState struct { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go index 4228216499..afd0f576b4 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state_test.go @@ -1571,6 +1571,75 @@ func TestCheckInstallPlanStatus(t *testing.T) { }), }, }, + { + description: "InstallPlanReferencedState/NoConditions/Failed/ToInstallPlanFailedState/Update/InstallPlanReasonComponentFailed/MultipleBundleConditions", + fields: fields{ + existingObjs: existingObjs{ + clientObjs: []runtime.Object{ + &v1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "ns", + }, + }, + }, + }, + namespace: "ns", + state: newInstallPlanReferencedState(&v1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "ns", + }, + }), + }, + args: args{ + now: &now, + status: &v1alpha1.InstallPlanStatus{ + Phase: v1alpha1.InstallPlanPhaseFailed, + Conditions: []v1alpha1.InstallPlanCondition{ + { + Type: v1alpha1.InstallPlanInstalled, + Status: corev1.ConditionFalse, + Reason: v1alpha1.InstallPlanReasonComponentFailed, + }, + }, + BundleLookups: []v1alpha1.BundleLookup{ + { + Conditions: []v1alpha1.BundleLookupCondition{ + { + Type: v1alpha1.BundleLookupPending, + Status: corev1.ConditionTrue, + Message: "encountered issue foo", + }, + }, + }, + { + Conditions: []v1alpha1.BundleLookupCondition{ + { + Type: v1alpha1.BundleLookupPending, + Status: corev1.ConditionTrue, + Message: "encountered issue bar", + }, + }, + }, + }, + }, + }, + want: want{ + transitioned: newInstallPlanFailedState(&v1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "ns", + }, + Status: v1alpha1.SubscriptionStatus{ + Conditions: []v1alpha1.SubscriptionCondition{ + planFailedCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanReasonComponentFailed), "encountered issue foo. encountered issue bar.", &now), + }, + LastUpdated: now, + }, + }), + }, + }, { description: "InstallPlanReferencedState/Conditions/Failed/ToInstallPlanFailedState/NoUpdate/InstallPlanReasonComponentFailed", fields: fields{ diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go index e7280e39b2..024cb3dd96 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/subscription/state.go @@ -511,23 +511,22 @@ func (i *installPlanReferencedState) CheckInstallPlanStatus(now *metav1.Time, cl } func extractMessage(status *v1alpha1.InstallPlanStatus) string { - str := "" - if len(status.BundleLookups) > 0 { - var b bytes.Buffer - for _, lookup := range status.BundleLookups { - if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown { - b.WriteString(cond.Message) - b.WriteString(".") - } - } - str = b.String() + if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown && cond.Message != "" { + return cond.Message } - if cond := status.GetCondition(v1alpha1.InstallPlanInstalled); cond.Status != corev1.ConditionUnknown { - if cond.Message != "" { - str = cond.Message + + var b bytes.Buffer + for _, lookup := range status.BundleLookups { + if cond := lookup.GetCondition(v1alpha1.BundleLookupPending); cond.Status != corev1.ConditionUnknown && cond.Message != "" { + if b.Len() != 0 { + b.WriteString(" ") + } + b.WriteString(cond.Message) + b.WriteString(".") } } - return str + + return b.String() } type installPlanKnownState struct { From cf30b9f757e9995b76ef7b45661f248d1b9f689e Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Mon, 19 Jul 2021 11:32:06 -0400 Subject: [PATCH 21/30] Use metadata-only watches when possible for Operator component APIs. The Operator adoption controller reads metadata.ownerReferences and metadata.labels to adopt Operator components, and the Operator controller itself maintains a list of component references in status.components.refs. For APIs without a status.conditions field, these references are equivalent to v1 ObjectReferences, and can be constructed using only the component's metadata. For APIs that do have a status.conditions field, the references are augmented with that information. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 608d6bf1991cdc671a94848e884290a4bc4d9804 --- .../cmd/olm/manager.go | 4 ++ .../operators/adoption_controller.go | 37 +++------- .../pkg/controller/operators/components.go | 70 +++++++++++++++++++ .../operators/decorators/operator.go | 5 ++ .../operators/decorators/operator_test.go | 1 + .../operators/operator_controller.go | 37 ++++------ .../pkg/controller/operators/suite_test.go | 4 +- .../cmd/olm/manager.go | 4 ++ .../operators/adoption_controller.go | 37 +++------- .../pkg/controller/operators/components.go | 70 +++++++++++++++++++ .../operators/decorators/operator.go | 5 ++ .../operators/operator_controller.go | 37 ++++------ 12 files changed, 207 insertions(+), 104 deletions(-) create mode 100644 staging/operator-lifecycle-manager/pkg/controller/operators/components.go create mode 100644 vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/components.go diff --git a/staging/operator-lifecycle-manager/cmd/olm/manager.go b/staging/operator-lifecycle-manager/cmd/olm/manager.go index 7f6b89012c..5e8e33ab73 100644 --- a/staging/operator-lifecycle-manager/cmd/olm/manager.go +++ b/staging/operator-lifecycle-manager/cmd/olm/manager.go @@ -4,6 +4,7 @@ import ( "context" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/selection" @@ -34,6 +35,9 @@ func Manager(ctx context.Context, debug bool) (ctrl.Manager, error) { setupLog := ctrl.Log.WithName("setup").V(1) scheme := runtime.NewScheme() + if err := metav1.AddMetaToScheme(scheme); err != nil { + return nil, err + } if err := operators.AddToScheme(scheme); err != nil { // ctrl.NewManager needs the Scheme to be populated // up-front so that the NewCache implementation we diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go index aa898c8a4e..8fb18ed92f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go @@ -19,6 +19,7 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -68,17 +69,17 @@ func (r *AdoptionReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&source.Kind{Type: &appsv1.Deployment{}}, enqueueCSV). Watches(&source.Kind{Type: &corev1.Namespace{}}, enqueueCSV). Watches(&source.Kind{Type: &corev1.Service{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueCSV). Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueProviders). Watches(&source.Kind{Type: &apiregistrationv1.APIService{}}, enqueueCSV). Watches(&source.Kind{Type: &operatorsv1alpha1.Subscription{}}, enqueueCSV). Watches(&source.Kind{Type: &operatorsv2.OperatorCondition{}}, enqueueCSV). + Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueCSV, builder.OnlyMetadata). Complete(reconcile.Func(r.ReconcileClusterServiceVersion)) if err != nil { return err @@ -350,24 +351,7 @@ func (r *AdoptionReconciler) disownFromAll(ctx context.Context, component runtim func (r *AdoptionReconciler) adoptees(ctx context.Context, operator decorators.Operator, csv *operatorsv1alpha1.ClusterServiceVersion) ([]runtime.Object, error) { // Note: We need to figure out how to dynamically add new list types here (or some equivalent) in // order to support operators composed of custom resources. - componentLists := []runtime.Object{ - &appsv1.DeploymentList{}, - &corev1.ServiceList{}, - &corev1.NamespaceList{}, - &corev1.ServiceAccountList{}, - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - &rbacv1.RoleList{}, - &rbacv1.RoleBindingList{}, - &rbacv1.ClusterRoleList{}, - &rbacv1.ClusterRoleBindingList{}, - &apiregistrationv1.APIServiceList{}, - &apiextensionsv1.CustomResourceDefinitionList{}, - &operatorsv1alpha1.SubscriptionList{}, - &operatorsv1alpha1.InstallPlanList{}, - &operatorsv1alpha1.ClusterServiceVersionList{}, - &operatorsv2.OperatorConditionList{}, - } + componentLists := componentLists() // Only resources that aren't already labelled are adoption candidates selector, err := operator.NonComponentSelector() @@ -403,7 +387,8 @@ func (r *AdoptionReconciler) adoptees(ctx context.Context, operator decorators.O // Pick up owned CRDs for _, provided := range csv.Spec.CustomResourceDefinitions.Owned { - crd := &apiextensionsv1.CustomResourceDefinition{} + crd := &metav1.PartialObjectMetadata{} + crd.SetGroupVersionKind(apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition")) if err := r.Get(ctx, types.NamespacedName{Name: provided.Name}, crd); err != nil { if !apierrors.IsNotFound(err) { // Inform requeue on transient error diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/components.go b/staging/operator-lifecycle-manager/pkg/controller/operators/components.go new file mode 100644 index 0000000000..63c48429dc --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/components.go @@ -0,0 +1,70 @@ +package operators + +import ( + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv2 "github.com/operator-framework/api/pkg/operators/v2" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" +) + +func componentLists() []runtime.Object { + return []runtime.Object{ + &appsv1.DeploymentList{}, + &corev1.ServiceList{}, + &corev1.NamespaceList{}, + &apiregistrationv1.APIServiceList{}, + &apiextensionsv1.CustomResourceDefinitionList{}, + &operatorsv1alpha1.SubscriptionList{}, + &operatorsv1alpha1.InstallPlanList{}, + &operatorsv1alpha1.ClusterServiceVersionList{}, + &operatorsv2.OperatorConditionList{}, + + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "SecretList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMapList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ServiceAccountList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "RoleList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "RoleBindingList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "ClusterRoleList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "ClusterRoleBindingList", + }, + }, + } +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go index 40252daa5b..4046f7ee09 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/reference" @@ -344,6 +345,10 @@ func NewComponent(component runtime.Object, scheme *runtime.Scheme) (*Component, if err := scheme.Convert(component, u, nil); err != nil { return nil, err } + // GVK may have been lost from PartialObjectMetadata during conversion. + if gvk := component.GetObjectKind().GroupVersionKind(); gvk != schema.EmptyObjectKind.GroupVersionKind() { + u.SetGroupVersionKind(gvk) + } c := &Component{ Unstructured: u, diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator_test.go index d19d2cab16..3c6ee8dbf9 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/decorators/operator_test.go @@ -88,6 +88,7 @@ func TestAddComponents(t *testing.T) { scheme := runtime.NewScheme() require.NoError(t, k8sscheme.AddToScheme(scheme)) require.NoError(t, operatorsv1alpha1.AddToScheme(scheme)) + require.NoError(t, metav1.AddMetaToScheme(scheme)) type fields struct { operator *operatorsv1.Operator diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go index 3153545ec4..62aa4e2d06 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go @@ -18,6 +18,7 @@ import ( kscheme "k8s.io/client-go/kubernetes/scheme" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -69,20 +70,22 @@ func (r *OperatorReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&operatorsv1.Operator{}). Watches(&source.Kind{Type: &appsv1.Deployment{}}, enqueueOperator). Watches(&source.Kind{Type: &corev1.Namespace{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueOperator). Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueOperator). Watches(&source.Kind{Type: &apiregistrationv1.APIService{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.Subscription{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.InstallPlan{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.ClusterServiceVersion{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv2.OperatorCondition{}}, enqueueOperator). - // TODO(njhale): Add WebhookConfigurations and ConfigMaps + // Metadata is sufficient to build component refs for + // GVKs that don't have a .status.conditions field. + Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueOperator, builder.OnlyMetadata). + // TODO(njhale): Add WebhookConfigurations Complete(r) } @@ -196,23 +199,7 @@ func (r *OperatorReconciler) updateComponents(ctx context.Context, operator *dec func (r *OperatorReconciler) listComponents(ctx context.Context, selector labels.Selector) ([]runtime.Object, error) { // Note: We need to figure out how to dynamically add new list types here (or some equivalent) in // order to support operators composed of custom resources. - componentLists := []runtime.Object{ - &appsv1.DeploymentList{}, - &corev1.NamespaceList{}, - &corev1.ServiceAccountList{}, - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - &rbacv1.RoleList{}, - &rbacv1.RoleBindingList{}, - &rbacv1.ClusterRoleList{}, - &rbacv1.ClusterRoleBindingList{}, - &apiextensionsv1.CustomResourceDefinitionList{}, - &apiregistrationv1.APIServiceList{}, - &operatorsv1alpha1.SubscriptionList{}, - &operatorsv1alpha1.InstallPlanList{}, - &operatorsv1alpha1.ClusterServiceVersionList{}, - &operatorsv2.OperatorConditionList{}, - } + componentLists := componentLists() opt := client.MatchingLabelsSelector{Selector: selector} for _, list := range componentLists { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/suite_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/suite_test.go index c1a90588a7..53f7d50fe6 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/suite_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/suite_test.go @@ -105,8 +105,8 @@ var _ = BeforeSuite(func() { Expect(cfg).ToNot(BeNil()) By("Setting up a controller manager") - err = AddToScheme(scheme) - Expect(err).ToNot(HaveOccurred()) + Expect(metav1.AddMetaToScheme(scheme)).To(Succeed()) + Expect(AddToScheme(scheme)).To(Succeed()) mgr, err := ctrl.NewManager(cfg, ctrl.Options{ MetricsBindAddress: "0", // Prevents conflicts with other test suites that might bind metrics Scheme: scheme, diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go index 7f6b89012c..5e8e33ab73 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/cmd/olm/manager.go @@ -4,6 +4,7 @@ import ( "context" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/selection" @@ -34,6 +35,9 @@ func Manager(ctx context.Context, debug bool) (ctrl.Manager, error) { setupLog := ctrl.Log.WithName("setup").V(1) scheme := runtime.NewScheme() + if err := metav1.AddMetaToScheme(scheme); err != nil { + return nil, err + } if err := operators.AddToScheme(scheme); err != nil { // ctrl.NewManager needs the Scheme to be populated // up-front so that the NewCache implementation we diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go index aa898c8a4e..8fb18ed92f 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/adoption_controller.go @@ -19,6 +19,7 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -68,17 +69,17 @@ func (r *AdoptionReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&source.Kind{Type: &appsv1.Deployment{}}, enqueueCSV). Watches(&source.Kind{Type: &corev1.Namespace{}}, enqueueCSV). Watches(&source.Kind{Type: &corev1.Service{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueCSV). - Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueCSV). - Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueCSV). Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueProviders). Watches(&source.Kind{Type: &apiregistrationv1.APIService{}}, enqueueCSV). Watches(&source.Kind{Type: &operatorsv1alpha1.Subscription{}}, enqueueCSV). Watches(&source.Kind{Type: &operatorsv2.OperatorCondition{}}, enqueueCSV). + Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueCSV, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueCSV, builder.OnlyMetadata). Complete(reconcile.Func(r.ReconcileClusterServiceVersion)) if err != nil { return err @@ -350,24 +351,7 @@ func (r *AdoptionReconciler) disownFromAll(ctx context.Context, component runtim func (r *AdoptionReconciler) adoptees(ctx context.Context, operator decorators.Operator, csv *operatorsv1alpha1.ClusterServiceVersion) ([]runtime.Object, error) { // Note: We need to figure out how to dynamically add new list types here (or some equivalent) in // order to support operators composed of custom resources. - componentLists := []runtime.Object{ - &appsv1.DeploymentList{}, - &corev1.ServiceList{}, - &corev1.NamespaceList{}, - &corev1.ServiceAccountList{}, - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - &rbacv1.RoleList{}, - &rbacv1.RoleBindingList{}, - &rbacv1.ClusterRoleList{}, - &rbacv1.ClusterRoleBindingList{}, - &apiregistrationv1.APIServiceList{}, - &apiextensionsv1.CustomResourceDefinitionList{}, - &operatorsv1alpha1.SubscriptionList{}, - &operatorsv1alpha1.InstallPlanList{}, - &operatorsv1alpha1.ClusterServiceVersionList{}, - &operatorsv2.OperatorConditionList{}, - } + componentLists := componentLists() // Only resources that aren't already labelled are adoption candidates selector, err := operator.NonComponentSelector() @@ -403,7 +387,8 @@ func (r *AdoptionReconciler) adoptees(ctx context.Context, operator decorators.O // Pick up owned CRDs for _, provided := range csv.Spec.CustomResourceDefinitions.Owned { - crd := &apiextensionsv1.CustomResourceDefinition{} + crd := &metav1.PartialObjectMetadata{} + crd.SetGroupVersionKind(apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition")) if err := r.Get(ctx, types.NamespacedName{Name: provided.Name}, crd); err != nil { if !apierrors.IsNotFound(err) { // Inform requeue on transient error diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/components.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/components.go new file mode 100644 index 0000000000..63c48429dc --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/components.go @@ -0,0 +1,70 @@ +package operators + +import ( + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv2 "github.com/operator-framework/api/pkg/operators/v2" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" +) + +func componentLists() []runtime.Object { + return []runtime.Object{ + &appsv1.DeploymentList{}, + &corev1.ServiceList{}, + &corev1.NamespaceList{}, + &apiregistrationv1.APIServiceList{}, + &apiextensionsv1.CustomResourceDefinitionList{}, + &operatorsv1alpha1.SubscriptionList{}, + &operatorsv1alpha1.InstallPlanList{}, + &operatorsv1alpha1.ClusterServiceVersionList{}, + &operatorsv2.OperatorConditionList{}, + + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "SecretList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMapList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ServiceAccountList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "RoleList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "RoleBindingList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "ClusterRoleList", + }, + }, + &metav1.PartialObjectMetadataList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: rbacv1.SchemeGroupVersion.String(), + Kind: "ClusterRoleBindingList", + }, + }, + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go index 40252daa5b..4046f7ee09 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators/operator.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/reference" @@ -344,6 +345,10 @@ func NewComponent(component runtime.Object, scheme *runtime.Scheme) (*Component, if err := scheme.Convert(component, u, nil); err != nil { return nil, err } + // GVK may have been lost from PartialObjectMetadata during conversion. + if gvk := component.GetObjectKind().GroupVersionKind(); gvk != schema.EmptyObjectKind.GroupVersionKind() { + u.SetGroupVersionKind(gvk) + } c := &Component{ Unstructured: u, diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go index 3153545ec4..62aa4e2d06 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/operator_controller.go @@ -18,6 +18,7 @@ import ( kscheme "k8s.io/client-go/kubernetes/scheme" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -69,20 +70,22 @@ func (r *OperatorReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&operatorsv1.Operator{}). Watches(&source.Kind{Type: &appsv1.Deployment{}}, enqueueOperator). Watches(&source.Kind{Type: &corev1.Namespace{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueOperator). - Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueOperator). - Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueOperator). Watches(&source.Kind{Type: &apiextensionsv1.CustomResourceDefinition{}}, enqueueOperator). Watches(&source.Kind{Type: &apiregistrationv1.APIService{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.Subscription{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.InstallPlan{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv1alpha1.ClusterServiceVersion{}}, enqueueOperator). Watches(&source.Kind{Type: &operatorsv2.OperatorCondition{}}, enqueueOperator). - // TODO(njhale): Add WebhookConfigurations and ConfigMaps + // Metadata is sufficient to build component refs for + // GVKs that don't have a .status.conditions field. + Watches(&source.Kind{Type: &corev1.ServiceAccount{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.Secret{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &corev1.ConfigMap{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.Role{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.RoleBinding{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRole{}}, enqueueOperator, builder.OnlyMetadata). + Watches(&source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, enqueueOperator, builder.OnlyMetadata). + // TODO(njhale): Add WebhookConfigurations Complete(r) } @@ -196,23 +199,7 @@ func (r *OperatorReconciler) updateComponents(ctx context.Context, operator *dec func (r *OperatorReconciler) listComponents(ctx context.Context, selector labels.Selector) ([]runtime.Object, error) { // Note: We need to figure out how to dynamically add new list types here (or some equivalent) in // order to support operators composed of custom resources. - componentLists := []runtime.Object{ - &appsv1.DeploymentList{}, - &corev1.NamespaceList{}, - &corev1.ServiceAccountList{}, - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - &rbacv1.RoleList{}, - &rbacv1.RoleBindingList{}, - &rbacv1.ClusterRoleList{}, - &rbacv1.ClusterRoleBindingList{}, - &apiextensionsv1.CustomResourceDefinitionList{}, - &apiregistrationv1.APIServiceList{}, - &operatorsv1alpha1.SubscriptionList{}, - &operatorsv1alpha1.InstallPlanList{}, - &operatorsv1alpha1.ClusterServiceVersionList{}, - &operatorsv2.OperatorConditionList{}, - } + componentLists := componentLists() opt := client.MatchingLabelsSelector{Selector: selector} for _, list := range componentLists { From 56a5579e3147f04e2cc394897580c905d1709c78 Mon Sep 17 00:00:00 2001 From: Nick Hale Date: Mon, 19 Jul 2021 21:34:24 -0400 Subject: [PATCH 22/30] fix(openshift): handle unquoted short max versions Add special handling for version shorthand commonly used in pipelines for Red Hat operator catalogs. Allows unquoted short versions to be used when specifying an operator's compatibility with versions of OpenShift; e.g. "olm.maxOpenShiftVersion": 4.8. Without this, OLM will only recognize quoted maxOpenShiftVersion properties; e.g. "olm.maxOpenShiftVersion": "4.8". Signed-off-by: Nick Hale Upstream-repository: operator-lifecycle-manager Upstream-commit: 1ebebdb37af7c64b800ff7ec3a04ddd0cccc2de7 --- .../clusteroperator_controller_test.go | 35 ++++++++++- .../controller/operators/openshift/helpers.go | 9 +-- .../operators/openshift/helpers_test.go | 59 +++++++++++++------ .../resolver/projection/properties_test.go | 23 +++++++- .../controller/operators/openshift/helpers.go | 9 +-- 5 files changed, 99 insertions(+), 36 deletions(-) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/clusteroperator_controller_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/clusteroperator_controller_test.go index 9b5c750ff5..6f00839d1b 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/clusteroperator_controller_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/clusteroperator_controller_test.go @@ -1,6 +1,8 @@ package openshift import ( + "fmt" + semver "github.com/blang/semver/v4" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -161,7 +163,7 @@ var _ = Describe("ClusterOperator controller", func() { withMax := func(version string) map[string]string { maxProperty := &api.Property{ Type: MaxOpenShiftVersionProperty, - Value: `"` + version + `"`, // Wrap in quotes so we don't break property marshaling + Value: version, } value, err := projection.PropertiesAnnotationFromPropertyList([]*api.Property{maxProperty}) Expect(err).ToNot(HaveOccurred()) @@ -170,7 +172,7 @@ var _ = Describe("ClusterOperator controller", func() { projection.PropertiesAnnotationKey: value, } } - incompatible.SetAnnotations(withMax(clusterVersion)) + incompatible.SetAnnotations(withMax(fmt.Sprintf(`"%s"`, clusterVersion))) // Wrap in quotes so we don't break property marshaling Eventually(func() error { return k8sClient.Create(ctx, incompatible) @@ -202,7 +204,7 @@ var _ = Describe("ClusterOperator controller", func() { // Set compatibility to the next minor version next := semver.MustParse(clusterVersion) Expect(next.IncrementMinor()).To(Succeed()) - incompatible.SetAnnotations(withMax(next.String())) + incompatible.SetAnnotations(withMax(fmt.Sprintf(`"%s"`, next.String()))) Eventually(func() error { return k8sClient.Update(ctx, incompatible) @@ -216,5 +218,32 @@ var _ = Describe("ClusterOperator controller", func() { Status: configv1.ConditionTrue, LastTransitionTime: fixedNow(), })) + + By("understanding unquoted short max versions; e.g. X.Y") + // Mimic common pipeline shorthand + v := semver.MustParse(clusterVersion) + short := fmt.Sprintf("%d.%d", v.Major, v.Minor) + incompatible.SetAnnotations(withMax(short)) + + Eventually(func() error { + return k8sClient.Update(ctx, incompatible) + }).Should(Succeed()) + + Eventually(func() ([]configv1.ClusterOperatorStatusCondition, error) { + err := k8sClient.Get(ctx, clusterOperatorName, co) + return co.Status.Conditions, err + }, timeout).Should(ContainElement(configv1.ClusterOperatorStatusCondition{ + Type: configv1.OperatorUpgradeable, + Status: configv1.ConditionFalse, + Reason: IncompatibleOperatorsInstalled, + Message: skews{ + { + namespace: ns.GetName(), + name: incompatible.GetName(), + maxOpenShiftVersion: short + ".0", + }, + }.String(), + LastTransitionTime: fixedNow(), + })) }) }) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go index 4dfd76c904..c7b0a00f2f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go @@ -2,7 +2,6 @@ package openshift import ( "context" - "encoding/json" "fmt" "strings" @@ -190,12 +189,7 @@ func maxOpenShiftVersion(csv *operatorsv1alpha1.ClusterServiceVersion) (*semver. continue } - var value string - if err := json.Unmarshal([]byte(property.Value), &value); err != nil { - errs = append(errs, err) - continue - } - + value := strings.Trim(property.Value, "\"") if value == "" { continue } @@ -203,6 +197,7 @@ func maxOpenShiftVersion(csv *operatorsv1alpha1.ClusterServiceVersion) (*semver. version, err := semver.ParseTolerant(value) if err != nil { errs = append(errs, err) + continue } if max == nil { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go index 92c7a22f3f..3e6a12dd6f 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers_test.go @@ -2,6 +2,7 @@ package openshift import ( "context" + "fmt" "testing" semver "github.com/blang/semver/v4" @@ -341,6 +342,11 @@ func TestIncompatibleOperators(t *testing.T) { namespace: "default", maxOpenShiftVersion: "1.0.0", }, + { + name: "chestnut", + namespace: "default", + maxOpenShiftVersion: "1.0", + }, }, expect: expect{ err: false, @@ -350,6 +356,11 @@ func TestIncompatibleOperators(t *testing.T) { namespace: "default", maxOpenShiftVersion: "1.0.0", }, + { + name: "chestnut", + namespace: "default", + maxOpenShiftVersion: "1.0.0", + }, }, }, }, @@ -463,7 +474,10 @@ func TestIncompatibleOperators(t *testing.T) { func TestMaxOpenShiftVersion(t *testing.T) { mustParse := func(s string) *semver.Version { - version := semver.MustParse(s) + version, err := semver.ParseTolerant(s) + if err != nil { + panic(fmt.Sprintf("bad version given for test case: %s", err)) + } return &version } @@ -485,7 +499,7 @@ func TestMaxOpenShiftVersion(t *testing.T) { }, { description: "Nothing", - in: []string{""}, + in: []string{`""`}, expect: expect{ err: false, max: nil, @@ -494,8 +508,8 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Nothing/Mixed", in: []string{ - "", - "1.0.0", + `""`, + `"1.0.0"`, }, expect: expect{ err: false, @@ -504,7 +518,7 @@ func TestMaxOpenShiftVersion(t *testing.T) { }, { description: "Garbage", - in: []string{"bad_version"}, + in: []string{`"bad_version"`}, expect: expect{ err: true, max: nil, @@ -513,8 +527,8 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Garbage/Mixed", in: []string{ - "bad_version", - "1.0.0", + `"bad_version"`, + `"1.0.0"`, }, expect: expect{ err: true, @@ -523,7 +537,7 @@ func TestMaxOpenShiftVersion(t *testing.T) { }, { description: "Single", - in: []string{"1.0.0"}, + in: []string{`"1.0.0"`}, expect: expect{ err: false, max: mustParse("1.0.0"), @@ -532,8 +546,8 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Multiple", in: []string{ - "1.0.0", - "2.0.0", + `"1.0.0"`, + `"2.0.0"`, }, expect: expect{ err: false, @@ -543,8 +557,8 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Duplicates", in: []string{ - "1.0.0", - "1.0.0", + `"1.0.0"`, + `"1.0.0"`, }, expect: expect{ err: false, @@ -554,9 +568,9 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Duplicates/NonMax", in: []string{ - "1.0.0", - "1.0.0", - "2.0.0", + `"1.0.0"`, + `"1.0.0"`, + `"2.0.0"`, }, expect: expect{ err: false, @@ -566,21 +580,30 @@ func TestMaxOpenShiftVersion(t *testing.T) { { description: "Ambiguous", in: []string{ - "1.0.0", - "1.0.0+1", + `"1.0.0"`, + `"1.0.0+1"`, }, expect: expect{ err: true, max: nil, }, }, + { + // Ensure unquoted short strings are accepted; e.g. X.Y + description: "Unquoted/Short", + in: []string{"4.8"}, + expect: expect{ + err: false, + max: mustParse("4.8"), + }, + }, } { t.Run(tt.description, func(t *testing.T) { var properties []*api.Property for _, max := range tt.in { properties = append(properties, &api.Property{ Type: MaxOpenShiftVersionProperty, - Value: `"` + max + `"`, // Wrap in quotes so we don't break property marshaling + Value: max, }) } diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/projection/properties_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/projection/properties_test.go index 6c71a82a7f..acde5acd76 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/projection/properties_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/resolver/projection/properties_test.go @@ -54,6 +54,16 @@ func TestPropertiesAnnotationFromPropertyList(t *testing.T) { }, expected: `{"properties":[{"type":"string","value":"hello"},{"type":"number","value":5},{"type":"array","value":[1,"two",3,"four"]},{"type":"object","value":{"hello":{"worl":"d"}}}]}`, }, + { + name: "unquoted string", + properties: []*api.Property{ + { + Type: "version", + Value: "4.8", + }, + }, + expected: `{"properties":[{"type":"version","value":4.8}]}`, + }, } { t.Run(tc.name, func(t *testing.T) { actual, err := projection.PropertiesAnnotationFromPropertyList(tc.properties) @@ -120,12 +130,23 @@ func TestPropertyListFromPropertiesAnnotation(t *testing.T) { { Type: "array", Value: `[1,"two",3,"four"]`, - }, { + }, + { Type: "object", Value: `{"hello":{"worl":"d"}}`, }, }, }, + { + name: "unquoted string values", + annotation: `{"properties":[{"type": "version","value": 4.8}]}`, + expected: []*api.Property{ + { + Type: "version", + Value: "4.8", + }, + }, + }, } { t.Run(tc.name, func(t *testing.T) { actual, err := projection.PropertyListFromPropertiesAnnotation(tc.annotation) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go index 4dfd76c904..c7b0a00f2f 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/openshift/helpers.go @@ -2,7 +2,6 @@ package openshift import ( "context" - "encoding/json" "fmt" "strings" @@ -190,12 +189,7 @@ func maxOpenShiftVersion(csv *operatorsv1alpha1.ClusterServiceVersion) (*semver. continue } - var value string - if err := json.Unmarshal([]byte(property.Value), &value); err != nil { - errs = append(errs, err) - continue - } - + value := strings.Trim(property.Value, "\"") if value == "" { continue } @@ -203,6 +197,7 @@ func maxOpenShiftVersion(csv *operatorsv1alpha1.ClusterServiceVersion) (*semver. version, err := semver.ParseTolerant(value) if err != nil { errs = append(errs, err) + continue } if max == nil { From a18a15545d8bb9b2500b71c8654c433acfa90e81 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 20 Jul 2021 08:42:48 -0400 Subject: [PATCH 23/30] remove unused scripts kube_deps is not used for pinning kube dependencies anymore the other scripts were used for older ways that olm integrated with openshift and are no longer needed Upstream-repository: operator-lifecycle-manager Upstream-commit: d918d71be9c8b752f3172b08e4c993823df95767 --- .../scripts/k8s_yaml_to_ansible_install.sh | 29 ------------------- .../scripts/k8s_yaml_to_ansible_remove.sh | 27 ----------------- .../scripts/kube_deps.sh | 20 ------------- .../scripts/pull_or_build_rh.sh | 7 ----- 4 files changed, 83 deletions(-) delete mode 100755 staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_install.sh delete mode 100755 staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_remove.sh delete mode 100755 staging/operator-lifecycle-manager/scripts/kube_deps.sh delete mode 100755 staging/operator-lifecycle-manager/scripts/pull_or_build_rh.sh diff --git a/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_install.sh b/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_install.sh deleted file mode 100755 index f1b1669977..0000000000 --- a/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_install.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# requires yq to be installed https://github.com/mikefarah/yq - -if [[ ${#@} < 2 ]]; then - echo "Usage: $0 manifests outfile" - echo "* manifests: directory of k8s manifests" - echo "* outfile: the ansible file to append" - exit 1 -fi - -manifests=$1 -outfile=$2 - -for filename in $manifests/*.yaml; do - kind=$(yq r "$filename" kind) - name=$(yq r "$filename" metadata.name) - cat <> $outfile - -- name: Apply $name $kind manifest - oc_obj: - state: present - kind: $kind - name: $name - namespace: operator-lifecycle-manager - files: - - "{{ mktemp.stdout }}/$(basename $filename)" -EOF -done diff --git a/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_remove.sh b/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_remove.sh deleted file mode 100755 index 7e92789720..0000000000 --- a/staging/operator-lifecycle-manager/scripts/k8s_yaml_to_ansible_remove.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -# requires yq to be installed https://github.com/mikefarah/yq - -if [[ ${#@} < 2 ]]; then - echo "Usage: $0 manifests outfile" - echo "* manifests: directory of k8s manifests" - echo "* outfile: the ansible file to append" - exit 1 -fi - -manifests=$1 -outfile=$2 - -for filename in $manifests/*.yaml; do - kind=$(yq r "$filename" kind) - name=$(yq r "$filename" metadata.name) - cat <> $outfile - -- name: Remove $name $kind manifest - oc_obj: - state: absent - kind: $kind - name: $name - namespace: operator-lifecycle-manager -EOF -done diff --git a/staging/operator-lifecycle-manager/scripts/kube_deps.sh b/staging/operator-lifecycle-manager/scripts/kube_deps.sh deleted file mode 100755 index fe07feaa8e..0000000000 --- a/staging/operator-lifecycle-manager/scripts/kube_deps.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -euo pipefail - -VERSION=${1#"v"} -if [ -z "$VERSION" ]; then - echo "Must specify version!" - exit 1 -fi -MODS=($( - curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod | - sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p' -)) -for MOD in "${MODS[@]}"; do - V=$( - go mod download -json "${MOD}@kubernetes-${VERSION}" | - sed -n 's|.*"Version": "\(.*\)".*|\1|p' - ) - go mod edit "-replace=${MOD}=${MOD}@${V}" -done -go get "k8s.io/kubernetes@v${VERSION}" diff --git a/staging/operator-lifecycle-manager/scripts/pull_or_build_rh.sh b/staging/operator-lifecycle-manager/scripts/pull_or_build_rh.sh deleted file mode 100755 index dc8697bd62..0000000000 --- a/staging/operator-lifecycle-manager/scripts/pull_or_build_rh.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -if ! docker pull "quay.io/coreos/olm:$1-rhel" || ! docker pull "quay.io/coreos/catalog:$1-rhel"; then - docker build -t "quay.io/coreos/olm:$1-rhel" -t "quay.io/coreos/catalog:$1-rhel" . - docker push "quay.io/coreos/olm:$1-rhel" - docker push "quay.io/coreos/catalog:$1-rhel" -fi From 327d2471ac41ae2af705b11db3c9be30ca1367af Mon Sep 17 00:00:00 2001 From: Ben Luddy Date: Tue, 20 Jul 2021 13:38:24 -0400 Subject: [PATCH 24/30] Temporarily use controller-runtime fork with data race patch. This should unblock our use for metadata-only watches for the moment. Signed-off-by: Ben Luddy Upstream-repository: operator-lifecycle-manager Upstream-commit: 9d14698a1330c690d6960f89d6b4db0571001194 --- staging/operator-lifecycle-manager/go.mod | 3 +++ staging/operator-lifecycle-manager/go.sum | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/staging/operator-lifecycle-manager/go.mod b/staging/operator-lifecycle-manager/go.mod index 8a02b55ae5..c03eb7b657 100644 --- a/staging/operator-lifecycle-manager/go.mod +++ b/staging/operator-lifecycle-manager/go.mod @@ -60,6 +60,9 @@ replace ( // controller runtime github.com/openshift/api => github.com/openshift/api v0.0.0-20200331152225-585af27e34fd // release-4.5 github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 // release-4.5 + // Patch for a race condition involving metadata-only + // informers until it can be resolved upstream: + sigs.k8s.io/controller-runtime v0.9.2 => github.com/benluddy/controller-runtime v0.9.3-0.20210720171926-9bcb99bd9bd3 // pinned because no tag supports 1.18 yet sigs.k8s.io/structured-merge-diff => sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 diff --git a/staging/operator-lifecycle-manager/go.sum b/staging/operator-lifecycle-manager/go.sum index 6a43a12331..f0a51b880f 100644 --- a/staging/operator-lifecycle-manager/go.sum +++ b/staging/operator-lifecycle-manager/go.sum @@ -133,6 +133,8 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benluddy/controller-runtime v0.9.3-0.20210720171926-9bcb99bd9bd3 h1:XnmeUOSdoo764dm67j2pKUNU7MqzB6a303w4ML2EhB4= +github.com/benluddy/controller-runtime v0.9.3-0.20210720171926-9bcb99bd9bd3/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -1724,8 +1726,6 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.20 h1:jLWvYcn/9pCws sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.20/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/controller-runtime v0.8.0/go.mod h1:v9Lbj5oX443uR7GXYY46E0EE2o7k2YxQ58GxVNeXSW4= sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8= -sigs.k8s.io/controller-runtime v0.9.2 h1:MnCAsopQno6+hI9SgJHKddzXpmv2wtouZz6931Eax+Q= -sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/controller-tools v0.6.0/go.mod h1:baRMVPrctU77F+rfAuH2uPqW93k6yQnZA2dhUOr7ihc= sigs.k8s.io/controller-tools v0.6.1 h1:nODRx2YrSNcaGd+90+CVC9SGEG6ygHlz3nSJmweR5as= From aa687ed16106bac84242871186721f6ca2525667 Mon Sep 17 00:00:00 2001 From: Alexander Greene Date: Wed, 21 Jul 2021 01:45:12 -0400 Subject: [PATCH 25/30] Update olm and catalog deployment templates The catalog deployment template only sets the readiness and liveness probes to HTTPS Scheme if the values.catalog.tlsKeyPath and values.catalog.tlsCertPath configurations are provided. These values should be set when the values.catalog.tlsSecret configuration is set The olm deployment template is also updated to use HTTPS when values.olm.tlsSecret is set. Signed-off-by: Alexander Greene Upstream-repository: operator-lifecycle-manager Upstream-commit: d49ce6af813089f176d0f101bf55df4dba25c5d9 --- .../templates/0000_50_olm_08-catalog-operator.deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml index 0af5686967..1f254e80b4 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml @@ -81,12 +81,12 @@ spec: httpGet: path: /healthz port: {{ .Values.catalog.service.internalPort }} - scheme: {{ if and .Values.catalog.tlsKeyPath .Values.catalog.tlsCertPath }}HTTPS{{ else }}HTTP{{end}} + scheme: {{ if .Values.catalog.tlsSecret }}HTTPS{{ else }}HTTP{{end}} readinessProbe: httpGet: path: /healthz port: {{ .Values.catalog.service.internalPort }} - scheme: {{ if and .Values.catalog.tlsKeyPath .Values.catalog.tlsCertPath }}HTTPS{{ else }}HTTP{{end}} + scheme: {{ if .Values.catalog.tlsSecret }}HTTPS{{ else }}HTTP{{end}} terminationMessagePolicy: FallbackToLogsOnError {{- if .Values.catalog.resources }} resources: From 6eb4891e5398fc401a06969605864144e33674f5 Mon Sep 17 00:00:00 2001 From: Anik Bhattacharjee Date: Wed, 21 Jul 2021 10:50:13 -0400 Subject: [PATCH 26/30] type(sub): Add ResolutionFailed condition type for subscription (#138) Upstream-repository: api Upstream-commit: a3fa2bd8d7c7f540824cda1b06f6677f198cfbb8 --- staging/api/pkg/operators/v1alpha1/subscription_types.go | 3 +++ .../api/pkg/operators/v1alpha1/subscription_types.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/staging/api/pkg/operators/v1alpha1/subscription_types.go b/staging/api/pkg/operators/v1alpha1/subscription_types.go index 7eaae1e68c..e048d4988c 100644 --- a/staging/api/pkg/operators/v1alpha1/subscription_types.go +++ b/staging/api/pkg/operators/v1alpha1/subscription_types.go @@ -102,6 +102,9 @@ const ( // SubscriptionInstallPlanFailed indicates that the installation of a Subscription's InstallPlan has failed. SubscriptionInstallPlanFailed SubscriptionConditionType = "InstallPlanFailed" + + // SubscriptionResolutionFailed indicates that the dependency resolution in the namespace in which the subscription is created has failed + SubscriptionResolutionFailed SubscriptionConditionType = "ResolutionFailed" ) const ( diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go index 7eaae1e68c..e048d4988c 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go @@ -102,6 +102,9 @@ const ( // SubscriptionInstallPlanFailed indicates that the installation of a Subscription's InstallPlan has failed. SubscriptionInstallPlanFailed SubscriptionConditionType = "InstallPlanFailed" + + // SubscriptionResolutionFailed indicates that the dependency resolution in the namespace in which the subscription is created has failed + SubscriptionResolutionFailed SubscriptionConditionType = "ResolutionFailed" ) const ( From a85c6423c68e7cc9ed1a943cd0a8f17b9b4ce891 Mon Sep 17 00:00:00 2001 From: Daniel Sover Date: Tue, 29 Jun 2021 12:57:21 -0400 Subject: [PATCH 27/30] feat: add GVK existence check for OLM supported resources by querying discovery in case of 404 not found errors when applying installplan steps. Upstream-repository: operator-lifecycle-manager Upstream-commit: c2674279c862b3b8264efddc931eee250c52beb5 --- .../controller/operators/catalog/not_found.go | 69 ++++++++++++++ .../controller/operators/catalog/operator.go | 12 +++ .../test/e2e/deprecated_e2e_test.go | 89 ++++++++++++++++++- .../test/e2e/installplan_e2e_test.go | 7 -- .../test/e2e/util_test.go | 14 +++ .../controller/operators/catalog/not_found.go | 69 ++++++++++++++ .../controller/operators/catalog/operator.go | 12 +++ 7 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 staging/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go create mode 100644 vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go new file mode 100644 index 0000000000..8cf4a3b991 --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go @@ -0,0 +1,69 @@ +package catalog + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" +) + +// gvkNotFoundError is returned from installplan execution when a step contains a GVK that is not found on cluster. +type gvkNotFoundError struct { + gvk schema.GroupVersionKind + name string +} + +func (g gvkNotFoundError) Error() string { + return fmt.Sprintf("api-server resource not found installing %s %s: GroupVersionKind %s not found on the cluster. %s", g.gvk.Kind, g.name, g.gvk, + "This API may have been deprecated and removed, see https://kubernetes.io/docs/reference/using-api/deprecation-guide/ for more information.") +} + +type DiscoveryQuerier interface { + QueryForGVK() error +} + +type DiscoveryQuerierFunc func() error + +func (d DiscoveryQuerierFunc) QueryForGVK() error { + return d() +} + +type discoveryQuerier struct { + client discovery.DiscoveryInterface +} + +func newDiscoveryQuerier(client discovery.DiscoveryInterface) *discoveryQuerier { + return &discoveryQuerier{client: client} +} + +// WithStepResource returns a DiscoveryQuerier which uses discovery to query for supported APIs on the server based on the provided step's GVK. +func (d *discoveryQuerier) WithStepResource(stepResource operatorsv1alpha1.StepResource) DiscoveryQuerier { + var f DiscoveryQuerierFunc = func() error { + gvk := schema.GroupVersionKind{Group: stepResource.Group, Version: stepResource.Version, Kind: stepResource.Kind} + + resourceList, err := d.client.ServerResourcesForGroupVersion(gvk.GroupVersion().String()) + if err != nil { + if errors.IsNotFound(err) { + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + return err + } + + if resourceList == nil { + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + + for _, resource := range resourceList.APIResources { + if resource.Kind == stepResource.Kind { + // this kind is supported for this particular GroupVersion + return nil + } + } + + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + return f +} diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index 6aec1d1ffe..6d057af5f0 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -11,6 +11,8 @@ import ( "sync" "time" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + errorwrap "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/connectivity" @@ -1774,6 +1776,8 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { ensurer := newStepEnsurer(kubeclient, crclient, dynamicClient) r := newManifestResolver(plan.GetNamespace(), o.lister.CoreV1().ConfigMapLister(), o.logger) + discoveryQuerier := newDiscoveryQuerier(o.opClient.KubernetesInterface().Discovery()) + // CRDs should be installed via the default OLM (cluster-admin) client and not the scoped client specified by the AttenuatedServiceAccount // the StepBuilder is currently only implemented for CRD types // TODO give the StepBuilder both OLM and scoped clients when it supports new scoped types @@ -2173,6 +2177,14 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } return nil }(i, step); err != nil { + if k8serrors.IsNotFound(err) { + // Check for APIVersions present in the installplan steps that are not available on the server. + // The check is made via discovery per step in the plan. Transient communication failures to the api-server are handled by the plan retry logic. + notFoundErr := discoveryQuerier.WithStepResource(step.Resource).QueryForGVK() + if notFoundErr != nil { + return notFoundErr + } + } return err } } diff --git a/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go index f411d7a174..f9d66cbeb1 100644 --- a/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go @@ -1,6 +1,89 @@ package e2e -// TODO +import ( + "context" + "time" -// v1beta1 CRD in installplan fails -// v1beta1 RBAC in an installplan fails + "github.com/blang/semver/v4" + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" +) + +var missingAPI = `{"apiVersion":"verticalpodautoscalers.autoscaling.k8s.io/v1","kind":"VerticalPodAutoscaler","metadata":{"name":"my.thing","namespace":"foo"}}` + +var _ = Describe("Not found APIs", func() { + BeforeEach(func() { + csv := newCSV("test-csv", testNamespace, "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.TODO(), &csv)).To(Succeed()) + }) + AfterEach(func() { + TearDown(testNamespace) + }) + + When("objects with APIs that are not on-cluster are created in the installplan", func() { + // each entry is an installplan with a deprecated resource + type payload struct { + name string + ip *operatorsv1alpha1.InstallPlan + errMessage string + } + + var tableEntries []table.TableEntry + tableEntries = []table.TableEntry{ + table.Entry("contains an entry with a missing API not found on cluster ", payload{ + name: "installplan contains a missing API", + ip: &operatorsv1alpha1.InstallPlan{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: *namespace, // this is necessary due to ginkgo table semantics, see https://github.com/onsi/ginkgo/issues/378 + Name: "test-plan-api", + }, + Spec: operatorsv1alpha1.InstallPlanSpec{ + Approval: operatorsv1alpha1.ApprovalAutomatic, + Approved: true, + ClusterServiceVersionNames: []string{}, + }, + Status: operatorsv1alpha1.InstallPlanStatus{ + Phase: operatorsv1alpha1.InstallPlanPhaseInstalling, + CatalogSources: []string{}, + Plan: []*operatorsv1alpha1.Step{ + { + Resolving: "test-csv", + Status: operatorsv1alpha1.StepStatusUnknown, + Resource: operatorsv1alpha1.StepResource{ + Name: "my.thing", + Group: "verticalpodautoscalers.autoscaling.k8s.io", + Version: "v1", + Kind: "VerticalPodAutoscaler", + Manifest: missingAPI, + }, + }, + }, + }, + }, + errMessage: "api-server resource not found installing VerticalPodAutoscaler my.thing: GroupVersionKind " + + "verticalpodautoscalers.autoscaling.k8s.io/v1, Kind=VerticalPodAutoscaler not found on the cluster", + }), + } + + table.DescribeTable("the ip enters a failed state with a helpful error message", func(tt payload) { + Expect(ctx.Ctx().Client().Create(context.Background(), tt.ip)).To(Succeed()) + Expect(ctx.Ctx().Client().Status().Update(context.Background(), tt.ip)).To(Succeed()) + + // The IP sits in the Installing phase with the GVK missing error + Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { + return tt.ip, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(tt.ip), tt.ip) + }).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseInstalling)), HaveMessage(tt.errMessage)) + + // Eventually the IP fails with the GVK missing error, after installplan retries, which is by default 1 minute. + Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { + return tt.ip, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(tt.ip), tt.ip) + }, 2*time.Minute).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseFailed)), HaveMessage(tt.errMessage)) + }, tableEntries...) + }) +}) diff --git a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index 9cb87e23d9..dea25b5b2c 100644 --- a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -16,7 +16,6 @@ import ( "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" - "github.com/onsi/gomega/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" @@ -53,12 +52,6 @@ import ( ) var _ = Describe("Install Plan", func() { - HavePhase := func(goal operatorsv1alpha1.InstallPlanPhase) types.GomegaMatcher { - return WithTransform(func(plan *operatorsv1alpha1.InstallPlan) operatorsv1alpha1.InstallPlanPhase { - return plan.Status.Phase - }, Equal(goal)) - } - AfterEach(func() { TearDown(testNamespace) }) diff --git a/staging/operator-lifecycle-manager/test/e2e/util_test.go b/staging/operator-lifecycle-manager/test/e2e/util_test.go index 284d14d7ee..18be4dddf3 100644 --- a/staging/operator-lifecycle-manager/test/e2e/util_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/util_test.go @@ -35,7 +35,9 @@ import ( "k8s.io/client-go/rest" k8scontrollerclient "sigs.k8s.io/controller-runtime/pkg/client" + gtypes "github.com/onsi/gomega/types" "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" controllerclient "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/controller-runtime/client" @@ -897,3 +899,15 @@ func deploymentReplicas(replicas int32) predicateFunc { func Apply(obj controllerclient.Object, changeFunc interface{}) func() error { return ctx.Ctx().SSAClient().Apply(context.Background(), obj, changeFunc) } + +func HavePhase(goal operatorsv1alpha1.InstallPlanPhase) gtypes.GomegaMatcher { + return WithTransform(func(plan *operatorsv1alpha1.InstallPlan) operatorsv1alpha1.InstallPlanPhase { + return plan.Status.Phase + }, Equal(goal)) +} + +func HaveMessage(goal string) gtypes.GomegaMatcher { + return WithTransform(func(plan *operatorsv1alpha1.InstallPlan) string { + return plan.Status.Message + }, ContainSubstring(goal)) +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go new file mode 100644 index 0000000000..8cf4a3b991 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/not_found.go @@ -0,0 +1,69 @@ +package catalog + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" +) + +// gvkNotFoundError is returned from installplan execution when a step contains a GVK that is not found on cluster. +type gvkNotFoundError struct { + gvk schema.GroupVersionKind + name string +} + +func (g gvkNotFoundError) Error() string { + return fmt.Sprintf("api-server resource not found installing %s %s: GroupVersionKind %s not found on the cluster. %s", g.gvk.Kind, g.name, g.gvk, + "This API may have been deprecated and removed, see https://kubernetes.io/docs/reference/using-api/deprecation-guide/ for more information.") +} + +type DiscoveryQuerier interface { + QueryForGVK() error +} + +type DiscoveryQuerierFunc func() error + +func (d DiscoveryQuerierFunc) QueryForGVK() error { + return d() +} + +type discoveryQuerier struct { + client discovery.DiscoveryInterface +} + +func newDiscoveryQuerier(client discovery.DiscoveryInterface) *discoveryQuerier { + return &discoveryQuerier{client: client} +} + +// WithStepResource returns a DiscoveryQuerier which uses discovery to query for supported APIs on the server based on the provided step's GVK. +func (d *discoveryQuerier) WithStepResource(stepResource operatorsv1alpha1.StepResource) DiscoveryQuerier { + var f DiscoveryQuerierFunc = func() error { + gvk := schema.GroupVersionKind{Group: stepResource.Group, Version: stepResource.Version, Kind: stepResource.Kind} + + resourceList, err := d.client.ServerResourcesForGroupVersion(gvk.GroupVersion().String()) + if err != nil { + if errors.IsNotFound(err) { + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + return err + } + + if resourceList == nil { + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + + for _, resource := range resourceList.APIResources { + if resource.Kind == stepResource.Kind { + // this kind is supported for this particular GroupVersion + return nil + } + } + + return gvkNotFoundError{gvk: gvk, name: stepResource.Name} + } + return f +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index 6aec1d1ffe..6d057af5f0 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -11,6 +11,8 @@ import ( "sync" "time" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + errorwrap "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/connectivity" @@ -1774,6 +1776,8 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { ensurer := newStepEnsurer(kubeclient, crclient, dynamicClient) r := newManifestResolver(plan.GetNamespace(), o.lister.CoreV1().ConfigMapLister(), o.logger) + discoveryQuerier := newDiscoveryQuerier(o.opClient.KubernetesInterface().Discovery()) + // CRDs should be installed via the default OLM (cluster-admin) client and not the scoped client specified by the AttenuatedServiceAccount // the StepBuilder is currently only implemented for CRD types // TODO give the StepBuilder both OLM and scoped clients when it supports new scoped types @@ -2173,6 +2177,14 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } return nil }(i, step); err != nil { + if k8serrors.IsNotFound(err) { + // Check for APIVersions present in the installplan steps that are not available on the server. + // The check is made via discovery per step in the plan. Transient communication failures to the api-server are handled by the plan retry logic. + notFoundErr := discoveryQuerier.WithStepResource(step.Resource).QueryForGVK() + if notFoundErr != nil { + return notFoundErr + } + } return err } } From b049064620cb1bda7e4cafff9ee38b900ec476a5 Mon Sep 17 00:00:00 2001 From: Alexander Greene Date: Wed, 21 Jul 2021 13:58:30 -0400 Subject: [PATCH 28/30] Update OLM Deployment template The olm deployment template will only use HTTPS when values.olm.tlsSecret is set in the values.yaml file. Signed-off-by: Alexander Greene Upstream-repository: operator-lifecycle-manager Upstream-commit: f1a3e5d917a8c7dc73c30a97a4099571c999f630 --- .../templates/0000_50_olm_07-olm-operator.deployment.yaml | 4 ++-- values.yaml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml index 2fac21b4db..942e8c56df 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml @@ -87,12 +87,12 @@ spec: httpGet: path: /healthz port: {{ .Values.olm.service.internalPort }} - scheme: {{ if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}HTTPS{{ else }}HTTP{{end}} + scheme: {{ if .Values.olm.tlsSecret }}HTTPS{{ else }}HTTP{{end}} readinessProbe: httpGet: path: /healthz port: {{ .Values.olm.service.internalPort }} - scheme: {{ if or .Values.olm.tlsSecret .Values.olm.clientCASecret }}HTTPS{{ else }}HTTP{{end}} + scheme: {{ if .Values.olm.tlsSecret }}HTTPS{{ else }}HTTP{{end}} terminationMessagePolicy: FallbackToLogsOnError env: - name: OPERATOR_NAMESPACE diff --git a/values.yaml b/values.yaml index d4e7826537..0045e10a11 100644 --- a/values.yaml +++ b/values.yaml @@ -45,8 +45,6 @@ catalog: internalPort: 8443 externalPort: 8443 clientCASecret: catalog-operator-serving-cert - tlsKeyPath: foo - tlsCertPath: bar tlsSecret: catalog-operator-serving-cert nodeSelector: kubernetes.io/os: linux From b77c2c0648c02bf21374aca741135fc9f3f2c639 Mon Sep 17 00:00:00 2001 From: kevinrizza Date: Wed, 21 Jul 2021 16:49:55 -0400 Subject: [PATCH 29/30] Add optional opm image argument to chart template Update catalog operator manifest chart template to include variable for new opmImage argument Upstream-repository: operator-lifecycle-manager Upstream-commit: 0ec7aca77a4cc0074a9d74a4bde50c574af7aea9 --- ...0_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml | 1 + manifests/0000_50_olm_08-catalog-operator.deployment.yaml | 1 + .../templates/0000_50_olm_08-catalog-operator.deployment.yaml | 3 +++ values.yaml | 1 + 4 files changed, 6 insertions(+) diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml index 0b1812f1ca..1cced579c1 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml @@ -49,6 +49,7 @@ spec: - '-namespace' - openshift-marketplace - -configmapServerImage=quay.io/operator-framework/configmap-operator-registry:latest + - -opmImage=quay.io/operator-framework/configmap-operator-registry:latest - -util-image - quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 - -writeStatusName diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml index 903a94ee9b..fdf5f685c8 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml @@ -50,6 +50,7 @@ spec: - '-namespace' - openshift-marketplace - -configmapServerImage=quay.io/operator-framework/configmap-operator-registry:latest + - -opmImage=quay.io/operator-framework/configmap-operator-registry:latest - -util-image - quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 - -writeStatusName diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml index 1f254e80b4..75676ef784 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml @@ -57,6 +57,9 @@ spec: {{- if .Values.catalog.commandArgs }} - {{ .Values.catalog.commandArgs }} {{- end }} + {{- if .Values.catalog.opmImageArgs }} + - {{ .Values.catalog.opmImageArgs }} + {{- end }} - -util-image - {{ .Values.catalog.image.ref }} {{- if .Values.writeStatusNameCatalog }} diff --git a/values.yaml b/values.yaml index 0045e10a11..7b476635ba 100644 --- a/values.yaml +++ b/values.yaml @@ -38,6 +38,7 @@ olm: memory: 160Mi catalog: replicaCount: 1 + opmImageArgs: -opmImage=quay.io/operator-framework/configmap-operator-registry:latest image: ref: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607 pullPolicy: IfNotPresent From ec51a3dd27f2f284c535fc436bc00825812b817d Mon Sep 17 00:00:00 2001 From: Alexander Greene Date: Wed, 21 Jul 2021 17:22:39 -0400 Subject: [PATCH 30/30] Update getMetricsFromPort to infer port number Problem: The getMetricsFromPod function assumes that metrics are exposed on port 8080. This function fails to retrieve metrics from the olm or catalog operator when the port is changed. Solution: Name the port in each of the deployments and update the getMetricsFromPod function to infer the port number from the deployments. Signed-off-by: Alexander Greene Upstream-repository: operator-lifecycle-manager Upstream-commit: 08a1d4b2f06fda1a6d6b4cadf779e1ce2259af3e --- ...operator.deployment.ibm-cloud-managed.yaml | 1 + ...000_50_olm_07-olm-operator.deployment.yaml | 1 + ...operator.deployment.ibm-cloud-managed.yaml | 1 + ...50_olm_08-catalog-operator.deployment.yaml | 1 + ...000_50_olm_07-olm-operator.deployment.yaml | 1 + ...50_olm_08-catalog-operator.deployment.yaml | 3 +- .../test/e2e/installplan_e2e_test.go | 4 +- .../test/e2e/metrics_e2e_test.go | 43 ++++++++++++------- 8 files changed, 36 insertions(+), 19 deletions(-) diff --git a/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml b/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml index 35e85add38..1a62fcd2d5 100644 --- a/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml +++ b/manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml @@ -62,6 +62,7 @@ spec: imagePullPolicy: IfNotPresent ports: - containerPort: 8443 + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/manifests/0000_50_olm_07-olm-operator.deployment.yaml b/manifests/0000_50_olm_07-olm-operator.deployment.yaml index 139bac5339..1a23661fae 100644 --- a/manifests/0000_50_olm_07-olm-operator.deployment.yaml +++ b/manifests/0000_50_olm_07-olm-operator.deployment.yaml @@ -63,6 +63,7 @@ spec: imagePullPolicy: IfNotPresent ports: - containerPort: 8443 + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml index 1cced579c1..f5da0de00e 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.ibm-cloud-managed.yaml @@ -64,6 +64,7 @@ spec: imagePullPolicy: IfNotPresent ports: - containerPort: 8443 + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml index fdf5f685c8..fde9d56591 100644 --- a/manifests/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/manifests/0000_50_olm_08-catalog-operator.deployment.yaml @@ -65,6 +65,7 @@ spec: imagePullPolicy: IfNotPresent ports: - containerPort: 8443 + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml index 942e8c56df..b71fbebd0d 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_07-olm-operator.deployment.yaml @@ -83,6 +83,7 @@ spec: imagePullPolicy: {{ .Values.olm.image.pullPolicy }} ports: - containerPort: {{ .Values.olm.service.internalPort }} + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml index 75676ef784..e9210d69ba 100644 --- a/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml +++ b/staging/operator-lifecycle-manager/deploy/chart/templates/0000_50_olm_08-catalog-operator.deployment.yaml @@ -79,7 +79,8 @@ spec: image: {{ .Values.catalog.image.ref }} imagePullPolicy: {{ .Values.catalog.image.pullPolicy }} ports: - - containerPort: {{ .Values.catalog.service.internalPort }} + - containerPort: {{ .Values.olm.service.internalPort }} + name: metrics livenessProbe: httpGet: path: /healthz diff --git a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index dea25b5b2c..9286b6086b 100644 --- a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -82,7 +82,7 @@ var _ = Describe("Install Plan", func() { BeforeEach(func() { counter = 0 - for _, metric := range getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8080") { + for _, metric := range getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator")) { if metric.Family == "installplan_warnings_total" { counter = metric.Value } @@ -182,7 +182,7 @@ var _ = Describe("Install Plan", func() { It("increments a metric counting the warning", func() { Eventually(func() []Metric { - return getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator"), "8080") + return getMetricsFromPod(ctx.Ctx().KubeClient(), getPodWithLabel(ctx.Ctx().KubeClient(), "app=catalog-operator")) }).Should(ContainElement(LikeMetric( WithFamily("installplan_warnings_total"), WithValueGreaterThan(counter), diff --git a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go index b0aa628035..56cef82d3e 100644 --- a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "regexp" + "strconv" "strings" "sync" @@ -80,7 +81,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("generates csv_abnormal metric for OLM pod", func() { - Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8080")).To(And( + Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"))).To(And( ContainElement(LikeMetric( WithFamily("csv_abnormal"), WithName(failingCSV.Name), @@ -108,7 +109,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes its associated CSV metrics", func() { // Verify that when the csv has been deleted, it deletes the corresponding CSV metrics - Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"), "8080")).ToNot(And( + Expect(getMetricsFromPod(c, getPodWithLabel(c, "app=olm-operator"))).ToNot(And( ContainElement(LikeMetric(WithFamily("csv_abnormal"), WithName(failingCSV.Name))), ContainElement(LikeMetric(WithFamily("csv_succeeded"), WithName(failingCSV.Name))), )) @@ -138,7 +139,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { // Verify metrics have been emitted for subscription Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), WithName("metric-subscription-for-create"), @@ -153,7 +154,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { // Verify metrics have been emitted for dependency resolution Eventually(func() bool { return Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric( WithFamily("olm_resolution_duration_seconds"), WithLabel("outcome", "failed"), @@ -168,7 +169,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-update", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-update")))) Eventually(func() error { s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{}) @@ -189,7 +190,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the old Subscription metric and emits the new metric", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(And( Not(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), @@ -223,7 +224,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the old subscription metric and emits the new metric(there is only one metric for the subscription)", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(And( Not(ContainElement(LikeMetric( WithFamily("subscription_sync_total"), @@ -253,7 +254,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-delete", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-delete")))) if subscriptionCleanup != nil { subscriptionCleanup() @@ -269,7 +270,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { It("deletes the Subscription metric", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).ShouldNot(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithName("metric-subscription-for-delete")))) }) }) @@ -312,7 +313,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("emits metrics for the catalogSource", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(And( ContainElement(LikeMetric( WithFamily("catalog_source_count"), @@ -332,7 +333,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("deletes the metrics for the CatalogSource", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(And( Not(ContainElement(LikeMetric( WithFamily("catalogsource_ready"), @@ -356,7 +357,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { }) It("emits metrics for the CatlogSource with a Value greater than 0", func() { Eventually(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(And( ContainElement(LikeMetric( WithFamily("catalogsource_ready"), @@ -366,7 +367,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { )), )) Consistently(func() []Metric { - return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator"), "8080") + return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }, "3m").Should(And( ContainElement(LikeMetric( WithFamily("catalogsource_ready"), @@ -395,7 +396,18 @@ func getPodWithLabel(client operatorclient.ClientInterface, label string) *corev return &podList.Items[0] } -func getMetricsFromPod(client operatorclient.ClientInterface, pod *corev1.Pod, port string) []Metric { +func extractMetricPortFromPod(pod *corev1.Pod) string { + for _, container := range pod.Spec.Containers { + for _, port := range container.Ports { + if port.Name == "metrics" { + return strconv.Itoa(int(port.ContainerPort)) + } + } + } + return "-1" +} + +func getMetricsFromPod(client operatorclient.ClientInterface, pod *corev1.Pod) []Metric { ctx.Ctx().Logf("querying pod %s/%s\n", pod.GetNamespace(), pod.GetName()) // assuming -tls-cert and -tls-key aren't used anywhere else as a parameter value @@ -417,14 +429,13 @@ func getMetricsFromPod(client operatorclient.ClientInterface, pod *corev1.Pod, p scheme = "http" } ctx.Ctx().Logf("Retrieving metrics using scheme %v\n", scheme) - mfs := make(map[string]*io_prometheus_client.MetricFamily) EventuallyWithOffset(1, func() error { raw, err := client.KubernetesInterface().CoreV1().RESTClient().Get(). Namespace(pod.GetNamespace()). Resource("pods"). SubResource("proxy"). - Name(net.JoinSchemeNamePort(scheme, pod.GetName(), port)). + Name(net.JoinSchemeNamePort(scheme, pod.GetName(), extractMetricPortFromPod(pod))). Suffix("metrics"). Do(context.Background()).Raw() if err != nil {