From 1bb9b68fceb89a4f6d0fcc561330a868f3f00573 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Thu, 31 Oct 2019 22:03:43 -0400 Subject: [PATCH 01/12] feat(resolver): rely on info from catalog to determine updates --- go.mod | 2 +- go.sum | 2 + pkg/controller/registry/resolver/evolver.go | 7 +- pkg/controller/registry/resolver/operators.go | 12 +- .../registry/resolver/operators_test.go | 9 +- pkg/controller/registry/resolver/querier.go | 18 +- .../registry/resolver/querier_test.go | 4 +- .../operator-registry/pkg/api/registry.pb.go | 105 +-- .../operator-registry/pkg/api/registry.proto | 2 + .../pkg/containertools/bundlereader.go | 186 ++++++ .../pkg/containertools/command.go | 66 ++ .../operator-registry/pkg/registry/bundle.go | 25 +- .../pkg/registry/interface.go | 3 + .../operator-registry/pkg/registry/types.go | 49 ++ .../operator-registry/pkg/sqlite/directory.go | 97 +-- .../operator-registry/pkg/sqlite/image.go | 239 +++++++ .../operator-registry/pkg/sqlite/load.go | 601 +++++++++++++++++- .../pkg/sqlite/migrations/000_init.go | 8 +- .../sqlite/migrations/001_related_images.go | 2 +- .../pkg/sqlite/migrations/002_bundle_path.go | 10 +- .../sqlite/migrations/003_required_apis.go | 2 +- .../sqlite/migrations/004_cascade_delete.go | 453 +++++++++++++ .../migrations/005_version_skiprange.go | 94 +++ .../pkg/sqlite/migrations/migrations.go | 11 + .../operator-registry/pkg/sqlite/migrator.go | 26 +- .../operator-registry/pkg/sqlite/query.go | 63 +- .../operator-registry/pkg/sqlite/remove.go | 67 ++ vendor/modules.txt | 3 +- 28 files changed, 1987 insertions(+), 179 deletions(-) create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/containertools/bundlereader.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/containertools/command.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/sqlite/image.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/004_cascade_delete.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/005_version_skiprange.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/sqlite/remove.go diff --git a/go.mod b/go.mod index 6840708553..ff74410be5 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b - github.com/operator-framework/operator-registry v1.5.1 + github.com/operator-framework/operator-registry v1.5.3 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 github.com/sirupsen/logrus v1.4.2 diff --git a/go.sum b/go.sum index 1e49a04857..58a8fc0eae 100644 --- a/go.sum +++ b/go.sum @@ -428,6 +428,8 @@ github.com/operator-framework/operator-registry v1.4.0 h1:yhI7ZeF6d7G588i2egoFjg github.com/operator-framework/operator-registry v1.4.0/go.mod h1:3nJcOSX6TKPpAbmGOAVvDxakZWgccyF0WgiJsKjPAzQ= github.com/operator-framework/operator-registry v1.5.1 h1:8ruUOG6IBDVTAXYWKsv6hwr4yv/0SFPFPAYGCpcv97E= github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= +github.com/operator-framework/operator-registry v1.5.3 h1:az83WDwgB+tHsmVn+tFq72yQBbaUAye8e4+KkDQmzLs= +github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= github.com/otiai10/copy v1.0.1 h1:gtBjD8aq4nychvRZ2CyJvFWAw0aja+VHazDdruZKGZA= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index f82487225b..8d630e4ddf 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -63,10 +63,11 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { continue } - o, err := NewOperatorFromBundle(bundle, op.Identifier(), op.SourceInfo().StartingCSV, *key) + o, err := NewOperatorFromBundle(bundle, op.SourceInfo().StartingCSV, *key) if err != nil { return errors.Wrap(err, "error parsing bundle") } + o.SetReplaces(op.Identifier()) if err := e.gen.AddOperator(o); err != nil { return errors.Wrap(err, "error calculating generation changes due to new bundle") } @@ -90,7 +91,7 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] return errors.Wrapf(err, "%s not found", s) } - o, err := NewOperatorFromBundle(bundle, "", s.StartingCSV, *key) + o, err := NewOperatorFromBundle(bundle, s.StartingCSV, *key) if err != nil { return errors.Wrap(err, "error parsing bundle") } @@ -123,7 +124,7 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error { // attempt to find a bundle that provides that api if bundle, key, err := e.querier.FindProvider(*api, initialSource); err == nil { // add a bundle that provides the api to the generation - o, err := NewOperatorFromBundle(bundle, "", "", *key) + o, err := NewOperatorFromBundle(bundle, "", *key) if err != nil { return errors.Wrap(err, "error parsing bundle") } diff --git a/pkg/controller/registry/resolver/operators.go b/pkg/controller/registry/resolver/operators.go index 82b0c56b46..203b8043c1 100644 --- a/pkg/controller/registry/resolver/operators.go +++ b/pkg/controller/registry/resolver/operators.go @@ -238,7 +238,7 @@ type Operator struct { var _ OperatorSurface = &Operator{} -func NewOperatorFromBundle(bundle *api.Bundle, replaces string, startingCSV string, sourceKey CatalogKey) (*Operator, error) { +func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey CatalogKey) (*Operator, error) { if bundle.CsvJson == "" { return nil, fmt.Errorf("no csv json found") } @@ -246,10 +246,6 @@ func NewOperatorFromBundle(bundle *api.Bundle, replaces string, startingCSV stri if err := json.Unmarshal([]byte(bundle.CsvJson), csv); err != nil { return nil, err } - r := replaces - if r == "" { - r, _ = csv.GetReplaces() - } version, _ := csv.GetVersion() parsedVersion, err := semver.ParseTolerant(version) @@ -269,7 +265,6 @@ func NewOperatorFromBundle(bundle *api.Bundle, replaces string, startingCSV stri return &Operator{ name: csv.GetName(), - replaces: r, version: v, providedAPIs: provided, requiredAPIs: required, @@ -311,7 +306,6 @@ func NewOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*Operator, return &Operator{ name: csv.GetName(), version: &csv.Spec.Version.Version, - replaces: csv.Spec.Replaces, providedAPIs: providedAPIs, requiredAPIs: requiredAPIs, sourceInfo: &ExistingOperator, @@ -334,6 +328,10 @@ func (o *Operator) Replaces() string { return o.replaces } +func (o *Operator) SetReplaces(replacing string) { + o.replaces = replacing +} + func (o *Operator) Package() string { return o.bundle.PackageName } diff --git a/pkg/controller/registry/resolver/operators_test.go b/pkg/controller/registry/resolver/operators_test.go index b2686a3f49..c0adf29174 100644 --- a/pkg/controller/registry/resolver/operators_test.go +++ b/pkg/controller/registry/resolver/operators_test.go @@ -1040,7 +1040,6 @@ func TestNewOperatorFromBundle(t *testing.T) { want: &Operator{ name: "testCSV", version: &version.Version, - replaces: "v1", providedAPIs: EmptyAPISet(), requiredAPIs: EmptyAPISet(), bundle: bundleNoAPIs, @@ -1059,9 +1058,8 @@ func TestNewOperatorFromBundle(t *testing.T) { replaces: "", }, want: &Operator{ - name: "testCSV", - version: &version.Version, - replaces: "v1", + name: "testCSV", + version: &version.Version, providedAPIs: APISet{ opregistry.APIKey{ Group: "crd.group.com", @@ -1110,7 +1108,6 @@ func TestNewOperatorFromBundle(t *testing.T) { providedAPIs: EmptyAPISet(), requiredAPIs: EmptyAPISet(), bundle: bundleNoAPIs, - replaces: "replaced", version: &version.Version, sourceInfo: &OperatorSourceInfo{ Package: "testPackage", @@ -1122,7 +1119,7 @@ func TestNewOperatorFromBundle(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := NewOperatorFromBundle(tt.args.bundle, tt.args.replaces, "", tt.args.sourceKey) + got, err := NewOperatorFromBundle(tt.args.bundle, "", tt.args.sourceKey) require.Equal(t, tt.wantErr, err) require.Equal(t, tt.want, got) }) diff --git a/pkg/controller/registry/resolver/querier.go b/pkg/controller/registry/resolver/querier.go index 93402334ea..b85d29a4e3 100644 --- a/pkg/controller/registry/resolver/querier.go +++ b/pkg/controller/registry/resolver/querier.go @@ -4,13 +4,10 @@ package resolver import ( "context" "fmt" - "strings" "github.com/blang/semver" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apimachinery/pkg/util/yaml" "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/client" @@ -180,22 +177,11 @@ func (q *NamespaceSourceQuerier) findChannelHead(currentVersion *semver.Version, return nil, err } - if latest.CsvJson == "" { + if latest.SkipRange == "" { return nil, nil } - dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(latest.CsvJson), 10) - unst := &unstructured.Unstructured{} - if err := dec.Decode(unst); err != nil { - return nil, err - } - - skipRange, ok := unst.GetAnnotations()[SkipPackageAnnotationKey] - if !ok { - return nil, nil - } - - r, err := semver.ParseRange(skipRange) + r, err := semver.ParseRange(latest.SkipRange) if err != nil { return nil, err } diff --git a/pkg/controller/registry/resolver/querier_test.go b/pkg/controller/registry/resolver/querier_test.go index 201579f4f0..53afae5f48 100644 --- a/pkg/controller/registry/resolver/querier_test.go +++ b/pkg/controller/registry/resolver/querier_test.go @@ -360,7 +360,7 @@ func TestNamespaceSourceQuerier_FindReplacement(t *testing.T) { require.NoError(t, err) nextBundle := &api.Bundle{CsvName: "test.v1", PackageName: "testPkg", ChannelName: "testChannel"} - latestBundle := &api.Bundle{CsvName: "latest", PackageName: "testPkg", ChannelName: "testChannel", CsvJson: string(csvJson), Object: []string{string(csvJson)}} + latestBundle := &api.Bundle{CsvName: "latest", PackageName: "testPkg", ChannelName: "testChannel", CsvJson: string(csvJson), Object: []string{string(csvJson)}, SkipRange: ">= 1.0.0-0 < 1.0.0-1556661308", Version: latestVersion.String()} csv.SetAnnotations(map[string]string{}) csvUnstNoAnnotationJson, err := json.Marshal(csv) @@ -491,7 +491,7 @@ func TestNamespaceSourceQuerier_FindReplacement(t *testing.T) { if err != nil { t.Log(err.Error()) } - require.Equal(t, tt.out.err, err) + require.Equal(t, tt.out.err, err, "%v", err) require.Equal(t, tt.out.bundle, got) require.Equal(t, tt.out.key, key) }) diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go index 06a9a93095..4430ca9586 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go @@ -168,6 +168,8 @@ type Bundle struct { BundlePath string `protobuf:"bytes,6,opt,name=bundlePath" json:"bundlePath,omitempty"` ProvidedApis []*GroupVersionKind `protobuf:"bytes,7,rep,name=providedApis" json:"providedApis,omitempty"` RequiredApis []*GroupVersionKind `protobuf:"bytes,8,rep,name=requiredApis" json:"requiredApis,omitempty"` + Version string `protobuf:"bytes,9,opt,name=version" json:"version,omitempty"` + SkipRange string `protobuf:"bytes,10,opt,name=skipRange" json:"skipRange,omitempty"` } func (m *Bundle) Reset() { *m = Bundle{} } @@ -231,6 +233,20 @@ func (m *Bundle) GetRequiredApis() []*GroupVersionKind { return nil } +func (m *Bundle) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Bundle) GetSkipRange() string { + if m != nil { + return m.SkipRange + } + return "" +} + type ChannelEntry struct { PackageName string `protobuf:"bytes,1,opt,name=packageName" json:"packageName,omitempty"` ChannelName string `protobuf:"bytes,2,opt,name=channelName" json:"channelName,omitempty"` @@ -985,48 +1001,49 @@ var _Registry_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("registry.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 680 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x6f, 0xd3, 0x30, - 0x14, 0x5f, 0xda, 0xad, 0xed, 0x5e, 0x2b, 0xb4, 0x99, 0x6d, 0x84, 0x80, 0xa6, 0xe2, 0x0b, 0x3b, - 0x55, 0x30, 0x40, 0x88, 0x03, 0x87, 0x8d, 0x41, 0x05, 0x0c, 0x34, 0x45, 0xfc, 0x39, 0x70, 0xf2, - 0x12, 0xd3, 0x86, 0x65, 0x4e, 0x66, 0x3b, 0x9b, 0xf6, 0x25, 0xb8, 0xf0, 0x3d, 0xf8, 0x8c, 0x28, - 0xb6, 0x93, 0x3a, 0x69, 0xba, 0x21, 0x21, 0xe0, 0xd6, 0xf7, 0xfc, 0xfe, 0xfc, 0xde, 0xcb, 0xef, - 0x67, 0x17, 0x6e, 0x70, 0x3a, 0x89, 0x84, 0xe4, 0x97, 0xa3, 0x94, 0x27, 0x32, 0x41, 0x6d, 0x92, - 0x46, 0xf8, 0x29, 0x74, 0x5f, 0x4c, 0x09, 0x63, 0x34, 0x46, 0x08, 0x96, 0x19, 0x39, 0xa5, 0xae, - 0x33, 0x74, 0x76, 0x56, 0x7d, 0xf5, 0x1b, 0xb9, 0xd0, 0x0d, 0xc4, 0xf9, 0xfb, 0xdc, 0xdd, 0x52, - 0xee, 0xc2, 0xc4, 0xf7, 0xa0, 0x7f, 0x44, 0x82, 0x13, 0x32, 0xa1, 0xb9, 0xd9, 0x94, 0x8c, 0x2f, - 0xa0, 0x6b, 0x42, 0x1a, 0x6b, 0xef, 0x40, 0x2f, 0xd0, 0xad, 0x85, 0xdb, 0x1a, 0xb6, 0x77, 0xfa, - 0xbb, 0x83, 0x11, 0x49, 0xa3, 0x91, 0xc1, 0xe3, 0x97, 0xa7, 0x68, 0x04, 0x28, 0xa4, 0x5f, 0x49, - 0x16, 0x4b, 0x73, 0xa6, 0x00, 0xb5, 0x55, 0xad, 0x86, 0x13, 0xcc, 0x60, 0x6d, 0xcc, 0x93, 0x2c, - 0xfd, 0x44, 0xb9, 0x88, 0x12, 0xf6, 0x36, 0x62, 0x21, 0xda, 0x80, 0x95, 0x49, 0xee, 0x33, 0x10, - 0xb4, 0x91, 0xcf, 0x77, 0xae, 0x83, 0x8a, 0xf9, 0x8c, 0x99, 0x23, 0x3e, 0x89, 0x58, 0x68, 0xba, - 0xa8, 0xdf, 0x68, 0x0b, 0x3a, 0x69, 0x9c, 0x71, 0x12, 0xbb, 0xcb, 0xca, 0x6b, 0x2c, 0xfc, 0xb3, - 0x05, 0x9d, 0xfd, 0x8c, 0x85, 0x71, 0x65, 0x61, 0x4e, 0x65, 0x61, 0x68, 0x08, 0xfd, 0x74, 0xb6, - 0x30, 0xd3, 0xce, 0x76, 0xe5, 0x11, 0xc1, 0xdc, 0x7c, 0xb6, 0xcb, 0x54, 0x7f, 0x23, 0x12, 0x66, - 0x10, 0x14, 0x66, 0x0e, 0x2d, 0x39, 0xfe, 0x46, 0x03, 0xe9, 0xae, 0x0c, 0xdb, 0x39, 0x34, 0x6d, - 0xa1, 0x6d, 0x80, 0x63, 0x85, 0xec, 0x88, 0xc8, 0xa9, 0xdb, 0x51, 0x49, 0x96, 0x07, 0x3d, 0x83, - 0x41, 0xca, 0x93, 0xf3, 0x28, 0xa4, 0xe1, 0x5e, 0x1a, 0x09, 0xb7, 0xab, 0x3e, 0xc4, 0xa6, 0xfa, - 0x10, 0xf5, 0x1d, 0xfa, 0x95, 0xd0, 0x3c, 0x95, 0xd3, 0xb3, 0x2c, 0xe2, 0x26, 0xb5, 0x77, 0x65, - 0xaa, 0x1d, 0x8a, 0xbf, 0x3b, 0x30, 0x30, 0x1f, 0xec, 0x25, 0x93, 0xfc, 0xb2, 0xbe, 0x1c, 0xe7, - 0xda, 0xe5, 0xb4, 0xe6, 0x97, 0x53, 0x8e, 0x6a, 0x6d, 0xcf, 0xf2, 0x20, 0x0f, 0x7a, 0x9c, 0xa6, - 0x31, 0x09, 0xa8, 0x30, 0xdb, 0x2b, 0x6d, 0xbc, 0x01, 0xe8, 0x30, 0x12, 0xd2, 0xd0, 0xd5, 0xa7, - 0x67, 0x19, 0x15, 0x12, 0xdf, 0x87, 0xf5, 0x31, 0xad, 0x39, 0x1b, 0x99, 0x3e, 0x85, 0xb5, 0x31, - 0x95, 0x9a, 0x02, 0x45, 0x9c, 0x0b, 0xdd, 0xf4, 0x64, 0x62, 0x33, 0xc1, 0x98, 0xbf, 0x31, 0x8a, - 0xc5, 0xa2, 0x76, 0x55, 0x76, 0x9f, 0xe1, 0x76, 0xd9, 0xe9, 0x35, 0x2b, 0xa4, 0xf2, 0xe7, 0x2d, - 0xf1, 0x13, 0x55, 0x78, 0x2f, 0x8e, 0x7d, 0xbd, 0x93, 0x53, 0xca, 0xa4, 0xb0, 0x0a, 0x37, 0xb3, - 0x1a, 0x9f, 0xc2, 0xe6, 0x98, 0x4a, 0x2b, 0xe7, 0xda, 0x14, 0x1b, 0x65, 0xeb, 0x4a, 0x94, 0xf3, - 0x02, 0xc0, 0x12, 0xb6, 0x34, 0xca, 0x23, 0xcd, 0x44, 0x5e, 0x42, 0xfc, 0x9b, 0xfa, 0xbe, 0x50, - 0xbb, 0x39, 0x24, 0x92, 0x0a, 0xf9, 0x1f, 0x1a, 0x1f, 0xe8, 0x1b, 0xae, 0xe8, 0xfc, 0x0f, 0x1a, - 0xef, 0xfe, 0x58, 0x81, 0x9e, 0x6f, 0x9e, 0x0b, 0xf4, 0x1c, 0x06, 0x96, 0x38, 0x04, 0xba, 0xa5, - 0x24, 0x3e, 0xaf, 0x17, 0x6f, 0x4d, 0x1d, 0x58, 0xcf, 0x02, 0x5e, 0x7a, 0xe0, 0xa0, 0xc7, 0x00, - 0x33, 0x15, 0xa1, 0x2d, 0x7d, 0x3f, 0xd4, 0x65, 0xe5, 0x0d, 0xec, 0x5c, 0xbc, 0x84, 0x1e, 0xc2, - 0x6a, 0x49, 0x74, 0xb4, 0x59, 0x24, 0x55, 0x24, 0xe6, 0xf5, 0x95, 0x5b, 0xfb, 0xf0, 0x12, 0x3a, - 0x80, 0x9b, 0x65, 0xc8, 0xab, 0x84, 0x17, 0xef, 0xda, 0x76, 0x35, 0xb9, 0xae, 0x9a, 0x7a, 0x95, - 0x8f, 0x70, 0x77, 0x4c, 0xa5, 0x75, 0x3b, 0x45, 0x54, 0x7c, 0x98, 0x92, 0x82, 0xe3, 0xb3, 0x72, - 0xcd, 0x5a, 0xf1, 0xd6, 0xed, 0x47, 0x4c, 0xdd, 0x6e, 0x6a, 0x0b, 0xfb, 0x4a, 0x28, 0xba, 0x8b, - 0x55, 0x4e, 0x20, 0xaf, 0xa8, 0x37, 0x2f, 0xa2, 0x3a, 0x34, 0x7f, 0x01, 0x34, 0xc3, 0x0c, 0x74, - 0xc7, 0x82, 0x56, 0xe7, 0xe9, 0x22, 0x5c, 0x5f, 0x00, 0x97, 0xdc, 0x5e, 0x5c, 0xb9, 0x1c, 0xba, - 0x59, 0x04, 0x8b, 0x8a, 0xbf, 0x53, 0x80, 0x0d, 0x7f, 0x67, 0xb3, 0x9b, 0x74, 0x31, 0x2b, 0xdb, - 0x4c, 0xf1, 0xda, 0xfc, 0xc7, 0x1d, 0xf5, 0xc7, 0xe5, 0xd1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xf7, 0x7c, 0x82, 0x4a, 0xca, 0x08, 0x00, 0x00, + // 701 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x56, 0x5d, 0x6f, 0xd3, 0x3c, + 0x14, 0x5e, 0xdb, 0xad, 0x1f, 0xa7, 0xd5, 0xab, 0xcd, 0xef, 0x36, 0x42, 0x99, 0xa6, 0xe2, 0x1b, + 0x76, 0x55, 0xc1, 0x00, 0x21, 0x2e, 0xb8, 0xd8, 0x18, 0x54, 0xc0, 0x40, 0x53, 0xc4, 0xc7, 0x05, + 0x57, 0x5e, 0x6b, 0x5a, 0xd3, 0xcc, 0xc9, 0x6c, 0x67, 0xd3, 0xfe, 0x04, 0x37, 0xfc, 0x47, 0x7e, + 0x07, 0x8a, 0xed, 0x24, 0x4e, 0x9a, 0x6e, 0x48, 0x08, 0xb8, 0xeb, 0x39, 0x3e, 0x1f, 0xcf, 0x79, + 0x72, 0x1e, 0xbb, 0xf0, 0x9f, 0xa0, 0x53, 0x26, 0x95, 0xb8, 0x1a, 0x46, 0x22, 0x54, 0x21, 0x6a, + 0x90, 0x88, 0xe1, 0x27, 0xd0, 0x7a, 0x3e, 0x23, 0x9c, 0xd3, 0x00, 0x21, 0x58, 0xe5, 0xe4, 0x8c, + 0x7a, 0xb5, 0x41, 0x6d, 0xaf, 0xe3, 0xeb, 0xdf, 0xc8, 0x83, 0xd6, 0x58, 0x5e, 0xbc, 0x4b, 0xdc, + 0x75, 0xed, 0x4e, 0x4d, 0x7c, 0x17, 0xba, 0x27, 0x64, 0x3c, 0x27, 0x53, 0x9a, 0x98, 0x55, 0xc9, + 0xf8, 0x12, 0x5a, 0x36, 0xa4, 0xb2, 0xf6, 0x1e, 0xb4, 0xc7, 0xa6, 0xb5, 0xf4, 0xea, 0x83, 0xc6, + 0x5e, 0x77, 0xbf, 0x37, 0x24, 0x11, 0x1b, 0x5a, 0x3c, 0x7e, 0x76, 0x8a, 0x86, 0x80, 0x26, 0xf4, + 0x0b, 0x89, 0x03, 0x65, 0xcf, 0x34, 0xa0, 0x86, 0xae, 0x55, 0x71, 0x82, 0x39, 0xac, 0x8f, 0x44, + 0x18, 0x47, 0x1f, 0xa9, 0x90, 0x2c, 0xe4, 0x6f, 0x18, 0x9f, 0xa0, 0x4d, 0x58, 0x9b, 0x26, 0x3e, + 0x0b, 0xc1, 0x18, 0xc9, 0x7c, 0x17, 0x26, 0x28, 0x9d, 0xcf, 0x9a, 0x09, 0xe2, 0x39, 0xe3, 0x13, + 0xdb, 0x45, 0xff, 0x46, 0xdb, 0xd0, 0x8c, 0x82, 0x58, 0x90, 0xc0, 0x5b, 0xd5, 0x5e, 0x6b, 0xe1, + 0x1f, 0x75, 0x68, 0x1e, 0xc6, 0x7c, 0x12, 0x14, 0x08, 0xab, 0x15, 0x08, 0x43, 0x03, 0xe8, 0x46, + 0x39, 0x61, 0xb6, 0x9d, 0xeb, 0x4a, 0x22, 0xc6, 0x0b, 0xf3, 0xb9, 0x2e, 0x5b, 0xfd, 0xb5, 0x0c, + 0xb9, 0x45, 0x90, 0x9a, 0x09, 0xb4, 0xf0, 0xf4, 0x2b, 0x1d, 0x2b, 0x6f, 0x6d, 0xd0, 0x48, 0xa0, + 0x19, 0x0b, 0xed, 0x02, 0x9c, 0x6a, 0x64, 0x27, 0x44, 0xcd, 0xbc, 0xa6, 0x4e, 0x72, 0x3c, 0xe8, + 0x29, 0xf4, 0x22, 0x11, 0x5e, 0xb0, 0x09, 0x9d, 0x1c, 0x44, 0x4c, 0x7a, 0x2d, 0xfd, 0x21, 0xb6, + 0xf4, 0x87, 0x28, 0x73, 0xe8, 0x17, 0x42, 0x93, 0x54, 0x41, 0xcf, 0x63, 0x26, 0x6c, 0x6a, 0xfb, + 0xda, 0x54, 0x37, 0xd4, 0xa5, 0xbd, 0x53, 0xa4, 0x7d, 0x07, 0x3a, 0x72, 0xce, 0x22, 0x9f, 0xf0, + 0x29, 0xf5, 0x40, 0x9f, 0xe5, 0x0e, 0xfc, 0xad, 0x06, 0x3d, 0xfb, 0xa1, 0x5f, 0x70, 0x25, 0xae, + 0xca, 0xa4, 0xd6, 0x6e, 0x24, 0xb5, 0xbe, 0x48, 0x6a, 0x46, 0x91, 0xc3, 0xba, 0xe3, 0x41, 0x7d, + 0x68, 0x0b, 0x1a, 0x05, 0x64, 0x4c, 0xa5, 0x65, 0x3d, 0xb3, 0xf1, 0x26, 0xa0, 0x63, 0x26, 0x95, + 0x5d, 0x73, 0x9f, 0x9e, 0xc7, 0x54, 0x2a, 0x7c, 0x0f, 0x36, 0x46, 0xb4, 0xe4, 0xac, 0x54, 0xc8, + 0x0c, 0xd6, 0x47, 0x54, 0x99, 0xd5, 0x49, 0xe3, 0x3c, 0x68, 0x45, 0xf3, 0xa9, 0xbb, 0x41, 0xd6, + 0xfc, 0x85, 0x51, 0x9c, 0xed, 0x6b, 0x14, 0xe5, 0xfa, 0x09, 0x6e, 0x67, 0x9d, 0x5e, 0xf1, 0x54, + 0x62, 0xbf, 0xdf, 0x12, 0x3f, 0xd6, 0x85, 0x0f, 0x82, 0xc0, 0x37, 0x9c, 0x9c, 0x51, 0xae, 0xa4, + 0x53, 0xb8, 0x5a, 0x0d, 0xf8, 0x0c, 0xb6, 0x46, 0x54, 0x39, 0x39, 0x37, 0xa6, 0xb8, 0x28, 0xeb, + 0xd7, 0xa2, 0x5c, 0x14, 0x0e, 0x56, 0xb0, 0x6d, 0x50, 0x9e, 0x98, 0x0d, 0x16, 0x19, 0xc4, 0x3f, + 0x79, 0x2f, 0x5c, 0x6a, 0x6e, 0x8e, 0x89, 0xa2, 0x52, 0xfd, 0x83, 0xc6, 0x47, 0xe6, 0x66, 0x4c, + 0x3b, 0xff, 0x85, 0xc6, 0xfb, 0xdf, 0xd7, 0xa0, 0xed, 0xdb, 0x67, 0x06, 0x3d, 0x83, 0x9e, 0x23, + 0x0e, 0x89, 0x6e, 0xe9, 0xab, 0x61, 0x51, 0x2f, 0xfd, 0x75, 0x7d, 0xe0, 0x3c, 0x27, 0x78, 0xe5, + 0x7e, 0x0d, 0x3d, 0x02, 0xc8, 0x55, 0x84, 0xb6, 0xcd, 0xbd, 0x52, 0x96, 0x55, 0xbf, 0xe7, 0xe6, + 0xe2, 0x15, 0xf4, 0x00, 0x3a, 0xd9, 0xa2, 0xa3, 0xad, 0x34, 0xa9, 0x20, 0xb1, 0x7e, 0x57, 0xbb, + 0x8d, 0x0f, 0xaf, 0xa0, 0x23, 0xf8, 0x3f, 0x0b, 0x79, 0x19, 0x8a, 0xf4, 0x3d, 0xdc, 0x2d, 0x26, + 0x97, 0x55, 0x53, 0xae, 0xf2, 0x01, 0x76, 0x46, 0x54, 0x39, 0xb7, 0x13, 0xa3, 0xf2, 0xfd, 0x8c, + 0xa4, 0x3b, 0x9e, 0x97, 0xab, 0xd6, 0x4a, 0x7f, 0xc3, 0x7d, 0xfc, 0xf4, 0xed, 0xa6, 0x59, 0x38, + 0xd4, 0x42, 0x31, 0x5d, 0x9c, 0x72, 0x12, 0xf5, 0xd3, 0x7a, 0x8b, 0x22, 0x2a, 0x43, 0xf3, 0x97, + 0x40, 0xb3, 0x9b, 0x81, 0xee, 0x38, 0xd0, 0xca, 0x7b, 0xba, 0x0c, 0xd7, 0x67, 0xc0, 0xd9, 0x6e, + 0x2f, 0xaf, 0x9c, 0x0d, 0x5d, 0x2d, 0x82, 0x65, 0xc5, 0xdf, 0x6a, 0xc0, 0x76, 0x7f, 0xf3, 0xd9, + 0x6d, 0xba, 0xcc, 0xcb, 0x56, 0xaf, 0x78, 0x69, 0xfe, 0xd3, 0xa6, 0xfe, 0xc3, 0xf3, 0xf0, 0x67, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x3c, 0x83, 0x36, 0x02, 0x09, 0x00, 0x00, } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto index 08ca758419..84cf90e441 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto +++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto @@ -46,6 +46,8 @@ message Bundle{ string bundlePath = 6; repeated GroupVersionKind providedApis = 7; repeated GroupVersionKind requiredApis = 8; + string version = 9; + string skipRange = 10; } message ChannelEntry{ diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/bundlereader.go b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/bundlereader.go new file mode 100644 index 0000000000..92f418b3fc --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/bundlereader.go @@ -0,0 +1,186 @@ +package containertools + +import ( + "archive/tar" + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" +) + +const ( + imageManifestName = "manifest.json" +) + +// imageManifest is the object format of container image manifest files +// use this type to parse manifest.json files inside container image blobs +type imageManifest struct { + Layers []string `json:”Layers”` +} + +type BundleReader struct { +} + +func NewBundleReader() *BundleReader { + return &BundleReader{} +} + +func (b *BundleReader) GetBundle(image, outputDir string) error { + r := NewCommandRunner(Podman) + + // Create the output directory if it doesn't exist + if _, err := os.Stat(outputDir); os.IsNotExist(err) { + os.Mkdir(outputDir, 0777) + } + + err := r.Pull(image) + if err != nil { + return err + } + + workingDir, err := ioutil.TempDir("./", "bundle_staging_") + if err != nil { + return err + } + defer os.RemoveAll(workingDir) + + rootTarfile := filepath.Join(workingDir, "bundle.tar") + + err = r.Save(image, rootTarfile) + if err != nil { + return err + } + + f, err := os.Open(rootTarfile) + if err != nil { + return err + } + defer f.Close() + + // Read the manifest.json file to find the right embedded tarball + layerTarballs, err := getManifestLayers(tar.NewReader(f)) + if err != nil { + return err + } + + // Untar the image layer tarballs and push the bundle manifests to the output directory + for _, tarball := range layerTarballs { + f, err = os.Open(rootTarfile) + if err != nil { + return err + } + defer f.Close() + + err = extractBundleManifests(tarball, outputDir, tar.NewReader(f)) + if err != nil { + return err + } + } + + return nil +} + +func getManifestLayers(tarReader *tar.Reader) ([]string, error) { + for { + header, err := tarReader.Next() + if err != nil { + if err == io.EOF { + return nil, fmt.Errorf("invalid bundle image: unable to find manifest.json") + } + return nil, err + } + + if header.Name == imageManifestName { + buf := new(bytes.Buffer) + buf.ReadFrom(tarReader) + b := buf.Bytes() + + manifests := make([]imageManifest, 0) + err := json.Unmarshal(b, &manifests) + if err != nil { + return nil, err + } + + if len(manifests) == 0 { + return nil, fmt.Errorf("invalid bundle image: manifest.json missing manifest data") + } + + topManifest := manifests[0] + + if len(topManifest.Layers) == 0 { + return nil, fmt.Errorf("invalid bundle image: manifest has no layers") + } + + return topManifest.Layers, nil + } + } +} + +func extractBundleManifests(layerTarball, outputDir string, tarReader *tar.Reader) error { + for { + header, err := tarReader.Next() + if err != nil { + if err == io.EOF { + return fmt.Errorf("Manifest error: Layer tarball does not exist in bundle") + } + return err + } + + if header.Typeflag == tar.TypeReg { + if header.Name == layerTarball { + // Found the embedded top layer tarball + layerReader := tar.NewReader(tarReader) + + err = extractTarballToDir(outputDir, layerReader) + if err != nil { + return err + } + } + + continue + } else { + return nil + } + } +} + +func extractTarballToDir(outputDir string, tarReader *tar.Reader) error { + for { + header, err := tarReader.Next() + if err != nil { + if err == io.EOF { + return nil + } + return err + } + + switch header.Typeflag { + case tar.TypeDir: + // Create the directory if it doesn't exist + directoryToWrite := filepath.Join(outputDir, header.Name) + if _, err := os.Stat(directoryToWrite); os.IsNotExist(err) { + os.Mkdir(directoryToWrite, 0777) + } + case tar.TypeReg: + buf := new(bytes.Buffer) + buf.ReadFrom(tarReader) + b := buf.Bytes() + + manifestToWrite := filepath.Join(outputDir, header.Name) + + m, err := os.Create(manifestToWrite) + if err != nil { + return err + } + defer m.Close() + + _, err = m.Write(b) + if err != nil { + return err + } + } + } +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/command.go b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/command.go new file mode 100644 index 0000000000..2a9e6de3ac --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/command.go @@ -0,0 +1,66 @@ +package containertools + +import ( + "fmt" + "os/exec" +) + +const ( + // Podman cli tool + Podman = "podman" + // Docker cli tool + Docker = "docker" +) + +// CommandRunner is configured to select a container cli tool and execute commands with that +// tooling. +type CommandRunner struct { + containerTool string +} + +// NewCommandRunner takes the containerTool as an input string and returns a CommandRunner to +// run commands with that cli tool +func NewCommandRunner(containerTool string) *CommandRunner { + r := &CommandRunner{} + + switch containerTool { + case Podman: + r.containerTool = Podman + case Docker: + r.containerTool = Docker + default: + r.containerTool = Podman + } + + return r +} + +// Pull takes a container image path hosted on a container registry and runs the pull command to +// download it onto the local environment +func (r *CommandRunner) Pull(image string) error { + args := []string{"pull", image} + + command := exec.Command(r.containerTool, args...) + + out, err := command.Output() + if err != nil { + return fmt.Errorf("error with %s %s: %s", command.Args, string(out), err) + } + + return nil +} + +// Save takes a local container image and runs the save commmand to convert the image into a specified +// tarball and push it to the local directory +func (r *CommandRunner) Save(image, tarFile string) error { + args := []string{"save", image, "-o", tarFile} + + command := exec.Command(r.containerTool, args...) + + out, err := command.Output() + if err != nil { + return fmt.Errorf("error with %s %s: %s", command.Args, string(out), err) + } + + return nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundle.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundle.go index b9ed042a6f..ec0198ca61 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundle.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/bundle.go @@ -28,13 +28,14 @@ func init() { } type Bundle struct { - Name string - Objects []*unstructured.Unstructured - Package string - Channel string - csv *ClusterServiceVersion - crds []*v1beta1.CustomResourceDefinition - cacheStale bool + Name string + Objects []*unstructured.Unstructured + Package string + Channel string + BundleImage string + csv *ClusterServiceVersion + crds []*v1beta1.CustomResourceDefinition + cacheStale bool } func NewBundle(name, pkgName, channelName string, objs ...*unstructured.Unstructured) *Bundle { @@ -170,12 +171,12 @@ func (b *Bundle) AllProvidedAPIsInBundle() error { return nil } -func (b *Bundle) Serialize() (csvName string, csvBytes []byte, bundleBytes []byte, err error) { +func (b *Bundle) Serialize() (csvName, bundleImage string, csvBytes []byte, bundleBytes []byte, err error) { csvCount := 0 for _, obj := range b.Objects { objBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) if err != nil { - return "", nil, nil, err + return "", "", nil, nil, err } bundleBytes = append(bundleBytes, objBytes...) @@ -183,16 +184,16 @@ func (b *Bundle) Serialize() (csvName string, csvBytes []byte, bundleBytes []byt csvName = obj.GetName() csvBytes, err = runtime.Encode(unstructured.UnstructuredJSONScheme, obj) if err != nil { - return "", nil, nil, err + return "", "", nil, nil, err } csvCount += 1 if csvCount > 1 { - return "", nil, nil, fmt.Errorf("two csvs found in one bundle") + return "", "", nil, nil, fmt.Errorf("two csvs found in one bundle") } } } - return csvName, csvBytes, bundleBytes, nil + return csvName, b.BundleImage, csvBytes, bundleBytes, nil } func (b *Bundle) Images() (map[string]struct{}, error) { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go index df2378088d..69a0102adf 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/interface.go @@ -8,7 +8,10 @@ import ( type Load interface { AddOperatorBundle(bundle *Bundle) error + AddBundlePackageChannels(manifest PackageManifest, bundle Bundle) error AddPackageChannels(manifest PackageManifest) error + RmPackageName(packageName string) error + ClearNonDefaultBundles(packageName string) error } type Query interface { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go index 4295d64e8a..7ca1c3e310 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go @@ -2,6 +2,7 @@ package registry import ( "fmt" + "strings" ) // APIKey stores GroupVersionKind for use as map keys @@ -74,3 +75,51 @@ type ChannelEntry struct { BundleName string Replaces string } + +// AnnotationsFile holds annotation information about a bundle +type AnnotationsFile struct { + // annotations is a list of annotations for a given bundle + Annotations Annotations `json:"annotations" yaml:"annotations"` +} + +// Annotations is a list of annotations for a given bundle +type Annotations struct { + // PackageName is the name of the overall package, ala `etcd`. + PackageName string `json:"operators.operatorframework.io.bundle.package.v1" yaml:"operators.operatorframework.io.bundle.package.v1"` + + // Channels are a comma separated list of the declared channels for the bundle, ala `stable` or `alpha`. + Channels string `json:"operators.operatorframework.io.bundle.channels.v1" yaml:"operators.operatorframework.io.bundle.channels.v1"` + + // DefaultChannelName is, if specified, the name of the default channel for the package. The + // default channel will be installed if no other channel is explicitly given. If the package + // has a single channel, then that channel is implicitly the default. + DefaultChannelName string `json:"operators.operatorframework.io.bundle.channel.default.v1" yaml:"operators.operatorframework.io.bundle.channel.default.v1"` +} + +// GetName returns the package name of the bundle +func (a *AnnotationsFile) GetName() string { + if a.Annotations.PackageName != "" { + return a.Annotations.PackageName + } + return "" +} + +// GetChannels returns the channels that this bundle should be added to +func (a *AnnotationsFile) GetChannels() []string { + if a.Annotations.Channels != "" { + return strings.Split(a.Annotations.Channels, ",") + } + return []string{} +} + +// GetDefaultChannelName returns the name of the default channel +func (a *AnnotationsFile) GetDefaultChannelName() string { + if a.Annotations.DefaultChannelName != "" { + return a.Annotations.DefaultChannelName + } + channels := a.GetChannels() + if len(channels) == 1 { + return channels[0] + } + return "" +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go index fedd8dfb96..fe708bf87d 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go @@ -107,7 +107,7 @@ func (d *DirectoryLoader) LoadBundleWalkFunc(path string, f os.FileInfo, err err log.Info("found csv, loading bundle") var errs []error - bundle, err := d.loadBundle(csv.GetName(), filepath.Dir(path)) + bundle, err := loadBundle(csv.GetName(), filepath.Dir(path)) if err != nil { errs = append(errs, fmt.Errorf("error loading objs in directory: %s", err)) } @@ -128,10 +128,56 @@ func (d *DirectoryLoader) LoadBundleWalkFunc(path string, f os.FileInfo, err err return utilerrors.NewAggregate(errs) } -// LoadBundle takes the directory that a CSV is in and assumes the rest of the objects in that directory +// LoadPackagesWalkFunc attempts to unmarshal the file at the given path into a PackageManifest resource. +// If unmarshaling is successful, the PackageManifest is added to the loader's store. +func (d *DirectoryLoader) LoadPackagesWalkFunc(path string, f os.FileInfo, err error) error { + if f == nil { + return fmt.Errorf("invalid file: %v", f) + } + + log := logrus.WithFields(logrus.Fields{"dir": d.directory, "file": f.Name(), "load": "package"}) + if f.IsDir() { + if strings.HasPrefix(f.Name(), ".") { + log.Info("skipping hidden directory") + return filepath.SkipDir + } + log.Info("directory") + return nil + } + + if strings.HasPrefix(f.Name(), ".") { + log.Info("skipping hidden file") + return nil + } + + fileReader, err := os.Open(path) + if err != nil { + return fmt.Errorf("unable to load package from file %s: %s", path, err) + } + + decoder := yaml.NewYAMLOrJSONDecoder(fileReader, 30) + manifest := registry.PackageManifest{} + if err = decoder.Decode(&manifest); err != nil { + if err != nil { + return fmt.Errorf("could not decode contents of file %s into package: %s", path, err) + } + + } + if manifest.PackageName == "" { + return nil + } + + if err := d.store.AddPackageChannels(manifest); err != nil { + return fmt.Errorf("error loading package into db: %s", err) + } + + return nil +} + +// loadBundle takes the directory that a CSV is in and assumes the rest of the objects in that directory // are part of the bundle. -func (d *DirectoryLoader) loadBundle(csvName string, dir string) (*registry.Bundle, error) { - log := logrus.WithFields(logrus.Fields{"dir": d.directory, "load": "bundle"}) +func loadBundle(csvName string, dir string) (*registry.Bundle, error) { + log := logrus.WithFields(logrus.Fields{"dir": dir, "load": "bundle"}) files, err := ioutil.ReadDir(dir) if err != nil { return nil, err @@ -178,46 +224,3 @@ func (d *DirectoryLoader) loadBundle(csvName string, dir string) (*registry.Bund return bundle, utilerrors.NewAggregate(errs) } - -// LoadPackagesWalkFunc attempts to unmarshal the file at the given path into a PackageManifest resource. -// If unmarshaling is successful, the PackageManifest is added to the loader's store. -func (d *DirectoryLoader) LoadPackagesWalkFunc(path string, f os.FileInfo, err error) error { - if f == nil { - return fmt.Errorf("invalid file: %v", f) - } - - log := logrus.WithFields(logrus.Fields{"dir": d.directory, "file": f.Name(), "load": "package"}) - if f.IsDir() { - if strings.HasPrefix(f.Name(), ".") { - log.Info("skipping hidden directory") - return filepath.SkipDir - } - log.Info("directory") - return nil - } - - if strings.HasPrefix(f.Name(), ".") { - log.Info("skipping hidden file") - return nil - } - - fileReader, err := os.Open(path) - if err != nil { - return fmt.Errorf("unable to load package from file %s: %s", path, err) - } - - decoder := yaml.NewYAMLOrJSONDecoder(fileReader, 30) - manifest := registry.PackageManifest{} - if err = decoder.Decode(&manifest); err != nil { - return fmt.Errorf("could not decode contents of file %s into package: %s", path, err) - } - if manifest.PackageName == "" { - return nil - } - - if err := d.store.AddPackageChannels(manifest); err != nil { - return fmt.Errorf("error loading package into db: %s", err) - } - - return nil -} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/image.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/image.go new file mode 100644 index 0000000000..6b8e257610 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/image.go @@ -0,0 +1,239 @@ +package sqlite + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/operator-framework/operator-registry/pkg/containertools" + "github.com/operator-framework/operator-registry/pkg/registry" +) + +// ImageLoader loads a bundle image of resources into the database +type ImageLoader struct { + store registry.Load + image string + directory string +} + +func NewSQLLoaderForImage(store registry.Load, image string) *ImageLoader { + return &ImageLoader{ + store: store, + image: image, + directory: "", + } +} + +func (i *ImageLoader) Populate() error { + + log := logrus.WithField("img", i.image) + + workingDir, err := ioutil.TempDir("./", "bundle_tmp") + if err != nil { + return err + } + defer os.RemoveAll(workingDir) + + // Pull the image and get the manifests + reader := containertools.NewBundleReader() + + err = reader.GetBundle(i.image, workingDir) + if err != nil { + return err + } + + i.directory = workingDir + + log.Infof("loading Bundle %s", i.image) + errs := make([]error, 0) + if err := i.LoadBundleFunc(); err != nil { + errs = append(errs, err) + } + + return utilerrors.NewAggregate(errs) +} + +// LoadBundleFunc walks the bundle directory. Looks for the metadata and manifests +// sub-directories to find the annotations.yaml file that will inform how the +// manifests of the bundle should be loaded into the database. +func (i *ImageLoader) LoadBundleFunc() error { + path := i.directory + manifests := filepath.Join(path, "manifests") + metadata := filepath.Join(path, "metadata") + + // Get annotations file + log := logrus.WithFields(logrus.Fields{"dir": i.directory, "file": metadata, "load": "annotations"}) + files, err := ioutil.ReadDir(metadata) + if err != nil { + return fmt.Errorf("unable to read directory %s: %s", metadata, err) + } + + annotationsFile := ®istry.AnnotationsFile{} + for _, f := range files { + fileReader, err := os.Open(filepath.Join(metadata, f.Name())) + if err != nil { + return fmt.Errorf("unable to read file %s: %s", f.Name(), err) + } + decoder := yaml.NewYAMLOrJSONDecoder(fileReader, 30) + err = decoder.Decode(&annotationsFile) + if err != nil || *annotationsFile == (registry.AnnotationsFile{}) { + continue + } else { + log.Info("found annotations file searching for csv") + } + } + + if *annotationsFile == (registry.AnnotationsFile{}) { + return fmt.Errorf("Could not find annotations.yaml file") + } + + err = i.loadManifests(manifests, annotationsFile) + if err != nil { + return err + } + + return nil +} + +func (i *ImageLoader) loadManifests(manifests string, annotationsFile *registry.AnnotationsFile) error { + log := logrus.WithFields(logrus.Fields{"dir": i.directory, "file": manifests, "load": "bundle"}) + + csv, err := i.findCSV(manifests) + if err != nil { + return err + } + + if csv.Object == nil { + return fmt.Errorf("csv is empty: %s", err) + } + + log.Info("found csv, loading bundle") + + // TODO: Check channels against what's in the database vs in the bundle csv + + bundle, err := loadBundle(csv.GetName(), manifests) + if err != nil { + return fmt.Errorf("error loading objs in directory: %s", err) + } + + if bundle == nil || bundle.Size() == 0 { + return fmt.Errorf("no bundle objects found") + } + + // set the bundleimage on the bundle + bundle.BundleImage = i.image + + if err := bundle.AllProvidedAPIsInBundle(); err != nil { + return fmt.Errorf("error checking provided apis in bundle %s: %s", bundle.Name, err) + } + + bcsv, err := bundle.ClusterServiceVersion() + if err != nil { + return fmt.Errorf("error getting csv from bundle %s: %s", bundle.Name, err) + } + + packageManifest, err := translateAnnotationsIntoPackage(annotationsFile, bcsv) + if err != nil { + return fmt.Errorf("Could not translate annotations file into packageManifest %s", err) + } + + if err := i.loadOperatorBundle(packageManifest, *bundle); err != nil { + return fmt.Errorf("Error adding package %s", err) + } + + // Finally let's delete all the old bundles + if err = i.store.ClearNonDefaultBundles(packageManifest.PackageName); err != nil { + return fmt.Errorf("Error deleting previous bundles: %s", err) + } + + return nil +} + +// findCSV looks through the bundle directory to find a csv +func (i *ImageLoader) findCSV(manifests string) (*unstructured.Unstructured, error) { + log := logrus.WithFields(logrus.Fields{"dir": i.directory, "find": "csv"}) + + files, err := ioutil.ReadDir(manifests) + if err != nil { + return nil, fmt.Errorf("unable to read directory %s: %s", manifests, err) + } + + var errs []error + for _, f := range files { + log = log.WithField("file", f.Name()) + if f.IsDir() { + log.Info("skipping directory") + continue + } + + if strings.HasPrefix(f.Name(), ".") { + log.Info("skipping hidden file") + continue + } + + path := filepath.Join(manifests, f.Name()) + fileReader, err := os.Open(path) + if err != nil { + errs = append(errs, fmt.Errorf("unable to read file %s: %s", path, err)) + continue + } + + dec := yaml.NewYAMLOrJSONDecoder(fileReader, 30) + unst := &unstructured.Unstructured{} + if err := dec.Decode(unst); err != nil { + continue + } + + if unst.GetKind() != ClusterServiceVersionKind { + continue + } + + return unst, nil + + } + + errs = append(errs, fmt.Errorf("no csv found in bundle")) + return nil, utilerrors.NewAggregate(errs) +} + +// loadOperatorBundle adds the package information to the loader's store +func (i *ImageLoader) loadOperatorBundle(manifest registry.PackageManifest, bundle registry.Bundle) error { + if manifest.PackageName == "" { + return nil + } + + if err := i.store.AddBundlePackageChannels(manifest, bundle); err != nil { + return fmt.Errorf("error loading bundle into db: %s", err) + } + + return nil +} + +// translateAnnotationsIntoPackage attempts to translate the channels.yaml file at the given path into a package.yaml +func translateAnnotationsIntoPackage(annotations *registry.AnnotationsFile, csv *registry.ClusterServiceVersion) (registry.PackageManifest, error) { + manifest := registry.PackageManifest{} + + channels := []registry.PackageChannel{} + for _, ch := range annotations.GetChannels() { + channels = append(channels, + registry.PackageChannel{ + Name: ch, + CurrentCSVName: csv.GetName(), + }) + } + + manifest = registry.PackageManifest{ + PackageName: annotations.GetName(), + DefaultChannelName: annotations.GetDefaultChannelName(), + Channels: channels, + } + + return manifest, nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go index c379569014..5436faa9d4 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go @@ -68,7 +68,7 @@ func (s *SQLLoader) AddOperatorBundle(bundle *registry.Bundle) error { } defer addImage.Close() - csvName, csvBytes, bundleBytes, err := bundle.Serialize() + csvName, bundleImage, csvBytes, bundleBytes, err := bundle.Serialize() if err != nil { return err } @@ -77,7 +77,7 @@ func (s *SQLLoader) AddOperatorBundle(bundle *registry.Bundle) error { return fmt.Errorf("csv name not found") } - if _, err := stmt.Exec(csvName, csvBytes, bundleBytes, nil); err != nil { + if _, err := stmt.Exec(csvName, csvBytes, bundleBytes, bundleImage); err != nil { return err } @@ -134,13 +134,22 @@ func (s *SQLLoader) AddPackageChannels(manifest registry.PackageManifest) error } defer addReplaces.Close() + var errs []error + if _, err := addPackage.Exec(manifest.PackageName); err != nil { - // This should be terminal - return err + err = s.updatePackageChannels(tx, manifest) + if err != nil { + errs = append(errs, err) + } + + if err := tx.Commit(); err != nil { + errs = append(errs, err) + } + + return utilerrors.NewAggregate(errs) } hasDefault := false - var errs []error for _, c := range manifest.Channels { if _, err := addChannel.Exec(c.Name, manifest.PackageName, c.CurrentCSVName); err != nil { errs = append(errs, err) @@ -274,6 +283,106 @@ func (s *SQLLoader) AddPackageChannels(manifest registry.PackageManifest) error return utilerrors.NewAggregate(errs) } +func (s *SQLLoader) ClearNonDefaultBundles(packageName string) error { + tx, err := s.db.Begin() + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + // First find the default channel for the package + getDefChan, err := tx.Prepare(fmt.Sprintf("select default_channel from package where name='%s'", packageName)) + if err != nil { + return err + } + defer getDefChan.Close() + + defaultChannelRows, err := getDefChan.Query() + if err != nil { + return err + } + defer defaultChannelRows.Close() + + if !defaultChannelRows.Next() { + return fmt.Errorf("no default channel found for package %s", packageName) + } + var defaultChannel sql.NullString + if err := defaultChannelRows.Scan(&defaultChannel); err != nil { + return err + } + + // Then get the head of the default channel + getChanHead, err := tx.Prepare(fmt.Sprintf("select head_operatorbundle_name from channel where name='%s'", defaultChannel.String)) + if err != nil { + return err + } + defer getChanHead.Close() + + chanHeadRows, err := getChanHead.Query() + if err != nil { + return err + } + defer chanHeadRows.Close() + + if !chanHeadRows.Next() { + return fmt.Errorf("no channel head found for default channel %s", defaultChannel.String) + } + var defChanHead sql.NullString + if err := chanHeadRows.Scan(&defChanHead); err != nil { + return err + } + + // Now get all the bundles that are not the head of the default channel + getChannelBundles, err := tx.Prepare(fmt.Sprintf("SELECT operatorbundle_name FROM channel_entry WHERE package_name='%s' AND operatorbundle_name!='%s'", packageName, defChanHead.String)) + if err != nil { + return err + } + defer getChanHead.Close() + + chanBundleRows, err := getChannelBundles.Query() + if err != nil { + return err + } + defer chanBundleRows.Close() + + bundles := make(map[string]struct{}, 0) + for chanBundleRows.Next() { + var bundleToUpdate sql.NullString + if err := chanBundleRows.Scan(&bundleToUpdate); err != nil { + return err + } + bundles[bundleToUpdate.String] = struct{}{} + } + + if len(bundles) > 0 { + bundlePredicates := []string{} + for bundle := range bundles { + bundlePredicates = append(bundlePredicates, fmt.Sprintf("name = '%s'", bundle)) + } + + var transactionPredicate string + if len(bundlePredicates) == 1 { + transactionPredicate = fmt.Sprintf("WHERE %s AND bundlepath != \"\"", bundlePredicates[0]) + } else { + transactionPredicate = fmt.Sprintf("WHERE (%s) AND bundlepath != \"\"", strings.Join(bundlePredicates, " OR ")) + } + + removeOldBundles, err := tx.Prepare(fmt.Sprintf("UPDATE operatorbundle SET bundle = null, csv = null %s", transactionPredicate)) + if err != nil { + return err + } + + _, err = removeOldBundles.Exec() + if err != nil { + return fmt.Errorf("Unable to remove previous bundles: %s", err) + } + } + + return tx.Commit() +} + func SplitCRDName(crdName string) (plural, group string, err error) { pluralGroup := strings.SplitN(crdName, ".", 2) if len(pluralGroup) != 2 { @@ -308,10 +417,14 @@ func (s *SQLLoader) getCSV(tx *sql.Tx, csvName string) (*registry.ClusterService return nil, err } + if !csvStringSQL.Valid { + return nil, fmt.Errorf("csv %s not stored for non-latest versions", csvName) + } + dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(csvStringSQL.String), 10) unst := &unstructured.Unstructured{} if err := dec.Decode(unst); err != nil { - return nil, err + return nil, fmt.Errorf("can't decode %s: %s", csvStringSQL.String, err) } csv := ®istry.ClusterServiceVersion{} @@ -342,6 +455,9 @@ func (s *SQLLoader) addAPIs(tx *sql.Tx, csv *registry.ClusterServiceVersion, cha defer addApiRequirer.Close() ownedCRDs, requiredCRDs, err := csv.GetCustomResourceDefintions() + if err != nil { + return err + } for _, crd := range ownedCRDs { plural, group, err := SplitCRDName(crd.Name) if err != nil { @@ -368,6 +484,9 @@ func (s *SQLLoader) addAPIs(tx *sql.Tx, csv *registry.ClusterServiceVersion, cha } ownedAPIs, requiredAPIs, err := csv.GetApiServiceDefinitions() + if err != nil { + return err + } for _, api := range ownedAPIs { if _, err := addAPI.Exec(api.Group, api.Version, api.Kind, api.Name); err != nil { return err @@ -380,9 +499,477 @@ func (s *SQLLoader) addAPIs(tx *sql.Tx, csv *registry.ClusterServiceVersion, cha if _, err := addAPI.Exec(api.Group, api.Version, api.Kind, api.Name); err != nil { return err } - if _, err := addAPIProvider.Exec(api.Group, api.Version, api.Kind, channelEntryId); err != nil { + if _, err := addApiRequirer.Exec(api.Group, api.Version, api.Kind, channelEntryId); err != nil { + return err + } + } + return nil +} +func (s *SQLLoader) getCSVNames(tx *sql.Tx, packageName string) ([]string, error) { + getID, err := tx.Prepare(` + SELECT DISTINCT channel_entry.operatorbundle_name + FROM channel_entry + WHERE channel_entry.package_name=?`) + + if err != nil { + return nil, err + } + defer getID.Close() + + rows, err := getID.Query(packageName) + if err != nil { + return nil, err + } + + var csvName string + csvNames := []string{} + for rows.Next() { + err := rows.Scan(&csvName) + if err != nil { + return nil, err + } + csvNames = append(csvNames, csvName) + } + + if err := rows.Close(); err != nil { + return nil, err + } + + return csvNames, nil +} + +func (s *SQLLoader) rmAPIs(tx *sql.Tx, csv *registry.ClusterServiceVersion) error { + rmAPI, err := tx.Prepare("delete from api where group_name=? AND version=? AND kind=?") + if err != nil { + return err + } + defer rmAPI.Close() + + ownedCRDs, _, err := csv.GetCustomResourceDefintions() + for _, crd := range ownedCRDs { + _, group, err := SplitCRDName(crd.Name) + if err != nil { + return err + } + if _, err := rmAPI.Exec(group, crd.Version, crd.Kind); err != nil { + return err + } + } + + return nil +} + +func (s *SQLLoader) RmPackageName(packageName string) error { + tx, err := s.db.Begin() + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + csvNames, err := s.getCSVNames(tx, packageName) + if err != nil { + return err + } + for _, csvName := range csvNames { + csv, err := s.getCSV(tx, csvName) + if csv != nil { + err = s.rmBundle(tx, csvName) + if err != nil { + return err + } + err = s.rmAPIs(tx, csv) + if err != nil { + return err + } + } else { + err = s.rmBundle(tx, csvName) + if err != nil { + return err + } + } + } + + return tx.Commit() +} + +func (s *SQLLoader) rmBundle(tx *sql.Tx, csvName string) error { + stmt, err := tx.Prepare("DELETE FROM operatorbundle WHERE operatorbundle.name=?") + if err != nil { + return err + } + defer stmt.Close() + + if _, err := stmt.Exec(csvName); err != nil { + return err + } + + return nil +} + +func (s *SQLLoader) AddBundlePackageChannels(manifest registry.PackageManifest, bundle registry.Bundle) error { + var errs []error + tx, err := s.db.Begin() + if err != nil { + return err + } + defer func() { + tx.Rollback() + }() + + stmt, err := tx.Prepare("insert into operatorbundle(name, csv, bundle, bundlepath) values(?, ?, ?, ?)") + if err != nil { + return err + } + defer stmt.Close() + + addImage, err := tx.Prepare("insert into related_image(image, operatorbundle_name) values(?,?)") + if err != nil { + return err + } + defer addImage.Close() + + csvName, bundleImage, csvBytes, bundleBytes, err := bundle.Serialize() + if err != nil { + return err + } + + if csvName == "" { + return fmt.Errorf("csv name not found") + } + + if _, err := stmt.Exec(csvName, csvBytes, bundleBytes, bundleImage); err != nil { + return err + } + + imgs, err := bundle.Images() + if err != nil { + return err + } + // TODO: bulk insert + for img := range imgs { + if _, err := addImage.Exec(img, csvName); err != nil { return err } } + + if err := tx.Commit(); err != nil { + return err + } + + if err := s.AddPackageChannels(manifest); err != nil { + errs = append(errs, err) + tx, err := s.db.Begin() + if err != nil { + errs = append(errs, err) + return utilerrors.NewAggregate(errs) + } + defer func() { + tx.Rollback() + }() + + if err := s.rmBundle(tx, csvName); err != nil { + errs = append(errs, err) + return utilerrors.NewAggregate(errs) + } + + if err := tx.Commit(); err != nil { + errs = append(errs, err) + } + + return utilerrors.NewAggregate(errs) + } + + return nil +} + +func (s *SQLLoader) updatePackageChannels(tx *sql.Tx, manifest registry.PackageManifest) error { + updateDefaultChannel, err := tx.Prepare("update package set default_channel = ? where name = ?") + if err != nil { + return err + } + defer updateDefaultChannel.Close() + + getDefaultChannel, err := tx.Prepare(`SELECT default_channel FROM package WHERE name = ? LIMIT 1`) + if err != nil { + return err + } + defer getDefaultChannel.Close() + + updateChannel, err := tx.Prepare("update channel set head_operatorbundle_name = ? where name = ? and package_name = ?") + if err != nil { + return err + } + defer updateChannel.Close() + + addChannelEntry, err := tx.Prepare("insert into channel_entry(channel_name, package_name, operatorbundle_name, depth) values(?, ?, ?, ?)") + if err != nil { + return err + } + defer addChannelEntry.Close() + + updateChannelEntry, err := tx.Prepare("update channel_entry set depth = ? where channel_name = ? and package_name = ? and operatorbundle_name = ?") + if err != nil { + return err + } + defer updateChannelEntry.Close() + + addReplaces, err := tx.Prepare("update channel_entry set replaces = ? where entry_id = ?") + if err != nil { + return err + } + defer addReplaces.Close() + + getDepth, err := tx.Prepare(` + SELECT channel_entry.depth, channel_entry.entry_id + FROM channel_entry + WHERE channel_name = ? and package_name = ? and operatorbundle_name =? + LIMIT 1`) + if err != nil { + return err + } + defer getDepth.Close() + + getChannelEntryID, err := tx.Prepare(` + SELECT channel_entry.entry_id + FROM channel_entry + WHERE channel_name = ? and package_name = ? and operatorbundle_name =? + LIMIT 1`) + if err != nil { + return err + } + defer getChannelEntryID.Close() + + updateDepth, err := tx.Prepare("update channel_entry set depth = depth + 1 where channel_name = ? and package_name = ? and operatorbundle_name = ?") + if err != nil { + return err + } + defer updateDepth.Close() + + removeSkipped, err := tx.Prepare("delete from channel_entry where channel_name = ? and package_name = ? and operatorbundle_name = ?") + if err != nil { + return err + } + defer removeSkipped.Close() + + getBundleIDNameFromDepthToHead, err := tx.Prepare(` + SELECT entry_id, operatorbundle_name + FROM channel_entry + WHERE depth < ? and channel_name = ? and package_name = ?`) + if err != nil { + return err + } + defer getBundleIDNameFromDepthToHead.Close() + + var errs []error + + // update head bundle name in channel table + for _, c := range manifest.Channels { + if _, err := updateChannel.Exec(c.CurrentCSVName, c.Name, manifest.PackageName); err != nil { + errs = append(errs, err) + continue + } + } + + // insert/replace default channel + defaultChannelName := manifest.GetDefaultChannel() + if defaultChannelName != "" { + if _, err := updateDefaultChannel.Exec(defaultChannelName, manifest.PackageName); err != nil { + errs = append(errs, err) + } + } // else assume default channel is already in db and need not be changed + + // For each channel, check where in update graph + // the bundle is attempted to be inserted. + // If not at the head of the channel then error + for _, c := range manifest.Channels { + // don't need to check if version has been inserted for a given channel + // because this is caught by primary key of operatorbundle table + + channelEntryCSV, err := s.getCSV(tx, c.CurrentCSVName) + + // check replaces + replaces, err := channelEntryCSV.GetReplaces() + if err != nil { + errs = append(errs, err) + break + } + + // where does the replaces fall in the update graph + rows, err := getDepth.Query(c.Name, manifest.PackageName, replaces) + if err != nil { + errs = append(errs, err) + continue + } + + var depth int64 + var currentID int64 + var replacedIDs []int64 + skips, err := channelEntryCSV.GetSkips() + if err != nil { + errs = append(errs, err) + continue + } + + if rows.Next() { + err := rows.Scan(&depth, ¤tID) + if err != nil { + errs = append(errs, err) + continue + } + // check if replaces not at the head of the channel + if depth != 0 { + // if not at the head of the channel, need to specify appropriate skips + if len(skips) != int(depth) { + errs = append(errs, fmt.Errorf("%s attempts to replace %s that is already replaced by another version", c.CurrentCSVName, replaces)) + return utilerrors.NewAggregate(errs) + } + skipmap := make(map[string]struct{}, 0) + for _, sk := range skips { + skipmap[sk] = struct{}{} + } + // get csv from depth to head for channel + skipped, err := getBundleIDNameFromDepthToHead.Query(depth, c.Name, manifest.PackageName) + if err != nil { + errs = append(errs, err) + continue + } + defer skipped.Close() + + // see if csvs match skips + var skip string + var replacedID int64 + for skipped.Next() { + err := skipped.Scan(&replacedID, &skip) + if err != nil { + errs = append(errs, err) + return utilerrors.NewAggregate(errs) + } + replacedIDs = append(replacedIDs, replacedID) + if _, ok := skipmap[skip]; !ok { + errs = append(errs, fmt.Errorf("%s attempts to replace %s that is already replaced by %s without specifying a skip", c.CurrentCSVName, replaces, skip)) + } + } + // aggregate all the errors instead of returning on first error + if len(errs) > 0 { + return utilerrors.NewAggregate(errs) + } + } + } else { + // specifies a replacement that is not in db + errs = append(errs, fmt.Errorf("%s specifies a replacement %s that cannot be found", c.CurrentCSVName, replaces)) + return utilerrors.NewAggregate(errs) + } + + if err := rows.Close(); err != nil { + errs = append(errs, err) + continue + } + + // insert version into head of channel + res, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, 0) + if err != nil { + errs = append(errs, err) + continue + } + + currentID, err = res.LastInsertId() + if err != nil { + errs = append(errs, err) + continue + } + + // update replacement to point to new head of channel + var replacedID int64 + rows, err = getChannelEntryID.Query(c.Name, manifest.PackageName, replaces) + if err != nil { + errs = append(errs, err) + continue + } + if rows.Next() { + err := rows.Scan(&replacedID) + if err != nil { + errs = append(errs, err) + } + } // else is not possible by previous SELECT statement on replaces + + if err := rows.Close(); err != nil { + errs = append(errs, err) + continue + } + + if _, err = addReplaces.Exec(replacedID, currentID); err != nil { + errs = append(errs, err) + continue + } + + // remove skips from graph + for _, skip := range skips { + if _, err := removeSkipped.Exec(c.Name, manifest.PackageName, skip); err != nil { + errs = append(errs, err) + continue + } + } + + // add APIs + if err := s.addAPIs(tx, channelEntryCSV, currentID); err != nil { + errs = append(errs, err) + continue + } + + // update depth to depth + 1 for replaced entry + _, err = updateDepth.Exec(c.Name, manifest.PackageName, replaces) + if err != nil { + errs = append(errs, err) + continue + } + + // insert dummy skips entries if needed or update the graph based on skips + depth = 1 + for _, skip := range skips { + // add dummy channel entry for the skipped version + skippedChannelEntry, err := addChannelEntry.Exec(c.Name, manifest.PackageName, skip, depth) + if err != nil { + errs = append(errs, err) + continue + } + + skippedID, err := skippedChannelEntry.LastInsertId() + if err != nil { + errs = append(errs, err) + continue + } + + // add another channel entry for the parent, which replaces the skipped + synthesizedChannelEntry, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, depth) + if err != nil { + errs = append(errs, err) + continue + } + + synthesizedID, err := synthesizedChannelEntry.LastInsertId() + if err != nil { + errs = append(errs, err) + continue + } + + if _, err = addReplaces.Exec(skippedID, synthesizedID); err != nil { + errs = append(errs, err) + continue + } + + if err := s.addAPIs(tx, channelEntryCSV, synthesizedID); err != nil { + errs = append(errs, err) + continue + } + + depth++ + } + } + + if errs != nil { + return utilerrors.NewAggregate(errs) + } return nil } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/000_init.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/000_init.go index 67df6476cb..00986acae8 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/000_init.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/000_init.go @@ -7,6 +7,10 @@ import ( var InitMigrationKey = 0 +func init() { + registerMigration(InitMigrationKey, initMigration) +} + var initMigration = &Migration{ Id: InitMigrationKey, Up: func(ctx context.Context, tx *sql.Tx) error { @@ -72,7 +76,3 @@ var initMigration = &Migration{ return err }, } - -func init() { - migrations[InitMigrationKey] = initMigration -} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/001_related_images.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/001_related_images.go index 392f722526..3b3c8c36b9 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/001_related_images.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/001_related_images.go @@ -14,7 +14,7 @@ import ( const RelatedImagesMigrationKey = 1 func init() { - migrations[RelatedImagesMigrationKey] = relatedImagesMigration + registerMigration(RelatedImagesMigrationKey, relatedImagesMigration) } // listBundles returns a list of operatorbundles as strings diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/002_bundle_path.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/002_bundle_path.go index 0ba0f09f06..b16c13d76b 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/002_bundle_path.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/002_bundle_path.go @@ -9,7 +9,7 @@ const BundlePathMigrationKey = 2 // Register this migration func init() { - migrations[BundlePathMigrationKey] = bundlePathMigration + registerMigration(BundlePathMigrationKey, bundlePathMigration) } var bundlePathMigration = &Migration{ @@ -23,13 +23,13 @@ var bundlePathMigration = &Migration{ return err }, Down: func(ctx context.Context, tx *sql.Tx) error { - foreingKeyOff := `PRAGMA foreign_keys = 0` + foreignKeyOff := `PRAGMA foreign_keys = 0` createTempTable := `CREATE TABLE operatorbundle_backup (name TEXT,csv TEXT,bundle TEXT)` backupTargetTable := `INSERT INTO operatorbundle_backup SELECT name,csv,bundle FROM operatorbundle` dropTargetTable := `DROP TABLE operatorbundle` renameBackUpTable := `ALTER TABLE operatorbundle_backup RENAME TO operatorbundle;` - foreingKeyOn := `PRAGMA foreign_keys = 1` - _, err := tx.ExecContext(ctx, foreingKeyOff) + foreignKeyOn := `PRAGMA foreign_keys = 1` + _, err := tx.ExecContext(ctx, foreignKeyOff) if err != nil { return err } @@ -49,7 +49,7 @@ var bundlePathMigration = &Migration{ if err != nil { return err } - _, err = tx.ExecContext(ctx, foreingKeyOn) + _, err = tx.ExecContext(ctx, foreignKeyOn) return err }, } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/003_required_apis.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/003_required_apis.go index dc1b451d74..08006a0300 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/003_required_apis.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/003_required_apis.go @@ -13,7 +13,7 @@ const RequiredApiMigrationKey = 3 // Register this migration func init() { - migrations[RequiredApiMigrationKey] = requiredApiMigration + registerMigration(RequiredApiMigrationKey, requiredApiMigration) } var requiredApiMigration = &Migration{ diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/004_cascade_delete.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/004_cascade_delete.go new file mode 100644 index 0000000000..6cdd9bed21 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/004_cascade_delete.go @@ -0,0 +1,453 @@ +package migrations + +import ( + "context" + "database/sql" +) + +var CascadeDeleteMigrationKey = 4 + +// Register this migration +func init() { + registerMigration(CascadeDeleteMigrationKey, cascadeDeleteMigration) +} + +var cascadeDeleteMigration = &Migration{ + Id: CascadeDeleteMigrationKey, + Up: func(ctx context.Context, tx *sql.Tx) error { + foreingKeyOff := `PRAGMA foreign_keys = 0` + renameTable := func(table string) string { + return `ALTER TABLE ` + table + ` RENAME TO ` + table + `_old;` + } + createNewOperatorBundleTable := ` + CREATE TABLE operatorbundle ( + name TEXT PRIMARY KEY, + csv TEXT, + bundle TEXT, + bundlepath TEXT);` + createNewPackageTable := ` + CREATE TABLE package ( + name TEXT PRIMARY KEY, + default_channel TEXT, + FOREIGN KEY(name, default_channel) REFERENCES channel(package_name,name) ON DELETE CASCADE + );` + createNewChannelTable := ` + CREATE TABLE channel ( + name TEXT, + package_name TEXT, + head_operatorbundle_name TEXT, + PRIMARY KEY(name, package_name), + FOREIGN KEY(head_operatorbundle_name) REFERENCES operatorbundle(name) ON DELETE CASCADE + );` + createNewChannelEntryTable := ` + CREATE TABLE channel_entry ( + entry_id INTEGER PRIMARY KEY, + channel_name TEXT, + package_name TEXT, + operatorbundle_name TEXT, + replaces INTEGER, + depth INTEGER, + FOREIGN KEY(replaces) REFERENCES channel_entry(entry_id) DEFERRABLE INITIALLY DEFERRED, + FOREIGN KEY(channel_name, package_name) REFERENCES channel(name, package_name) ON DELETE CASCADE + );` + createNewAPIProviderTable := ` + CREATE TABLE api_provider ( + group_name TEXT, + version TEXT, + kind TEXT, + channel_entry_id INTEGER, + PRIMARY KEY(group_name, version, kind, channel_entry_id), + FOREIGN KEY(channel_entry_id) REFERENCES channel_entry(entry_id) ON DELETE CASCADE, + FOREIGN KEY(group_name, version, kind) REFERENCES api(group_name, version, kind) + );` + createNewRelatedImageTable := ` + CREATE TABLE related_image ( + image TEXT, + operatorbundle_name TEXT, + FOREIGN KEY(operatorbundle_name) REFERENCES operatorbundle(name) ON DELETE CASCADE + );` + createNewAPIRequirerTable := ` + CREATE TABLE api_requirer ( + group_name TEXT, + version TEXT, + kind TEXT, + channel_entry_id INTEGER, + PRIMARY KEY(group_name, version, kind, channel_entry_id), + FOREIGN KEY(channel_entry_id) REFERENCES channel_entry(entry_id) ON DELETE CASCADE, + FOREIGN KEY(group_name, version, kind) REFERENCES api(group_name, version, kind) + );` + newTableTransfer := func(table string) string { + return `INSERT INTO ` + table + ` SELECT * FROM "` + table + `_old"` + } + dropTable := func(table string) string { + return `DROP TABLE "` + table + `_old"` + } + foreingKeyOn := `PRAGMA foreign_keys = 1` + + _, err := tx.ExecContext(ctx, foreingKeyOff) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewOperatorBundleTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewPackageTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewChannelTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewChannelEntryTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewAPIProviderTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewRelatedImageTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createNewAPIRequirerTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, newTableTransfer(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, foreingKeyOn) + return err + }, + Down: func(ctx context.Context, tx *sql.Tx) error { + foreingKeyOff := `PRAGMA foreign_keys = 0` + renameTable := func(table string) string { + return `ALTER TABLE ` + table + ` RENAME TO ` + table + `_old;` + } + createBackupOperatorBundleTable := ` + CREATE TABLE operatorbundle ( + name TEXT PRIMARY KEY, + csv TEXT UNIQUE, + bundle TEXT, + bundlepath TEXT);` + createBackupPackageTable := ` + CREATE TABLE IF NOT EXISTS package ( + name TEXT PRIMARY KEY, + default_channel TEXT, + FOREIGN KEY(name, default_channel) REFERENCES channel(package_name,name) + );` + createBackupChannelTable := ` + CREATE TABLE IF NOT EXISTS channel ( + name TEXT, + package_name TEXT, + head_operatorbundle_name TEXT, + PRIMARY KEY(name, package_name), + FOREIGN KEY(package_name) REFERENCES package(name), + FOREIGN KEY(head_operatorbundle_name) REFERENCES operatorbundle(name) + );` + createBackupChannelEntryTable := ` + CREATE TABLE IF NOT EXISTS channel_entry ( + entry_id INTEGER PRIMARY KEY, + channel_name TEXT, + package_name TEXT, + operatorbundle_name TEXT, + replaces INTEGER, + depth INTEGER, + FOREIGN KEY(replaces) REFERENCES channel_entry(entry_id) DEFERRABLE INITIALLY DEFERRED, + FOREIGN KEY(channel_name, package_name) REFERENCES channel(name, package_name) + );` + createBackupAPIProviderTable := ` + CREATE TABLE IF NOT EXISTS api_provider ( + group_name TEXT, + version TEXT, + kind TEXT, + channel_entry_id INTEGER, + FOREIGN KEY(channel_entry_id) REFERENCES channel_entry(entry_id), + FOREIGN KEY(group_name, version, kind) REFERENCES api(group_name, version, kind) + );` + createBackupRelatedImageTable := ` + CREATE TABLE IF NOT EXISTS related_image ( + image TEXT, + operatorbundle_name TEXT, + FOREIGN KEY(operatorbundle_name) REFERENCES operatorbundle(name) + );` + createBackupAPIRequirerTable := ` + CREATE TABLE IF NOT EXISTS api_requirer ( + group_name TEXT, + version TEXT, + kind TEXT, + channel_entry_id INTEGER, + FOREIGN KEY(channel_entry_id) REFERENCES channel_entry(entry_id), + FOREIGN KEY(group_name, version, kind) REFERENCES api(group_name, version, kind) + );` + backupTableTransfer := func(table string) string { + return `INSERT INTO ` + table + ` SELECT * FROM "` + table + `_old"` + } + dropTable := func(table string) string { + return `DROP TABLE "` + table + `_old"` + } + + foreingKeyOn := `PRAGMA foreign_keys = 1` + + _, err := tx.ExecContext(ctx, foreingKeyOff) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, renameTable(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupOperatorBundleTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupPackageTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupChannelTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupChannelEntryTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupAPIProviderTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupRelatedImageTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, createBackupAPIRequirerTable) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`operatorbundle`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`package`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`channel`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`channel_entry`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`api_provider`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`related_image`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, backupTableTransfer(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, dropTable(`api_requirer`)) + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, foreingKeyOn) + return err + }, +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/005_version_skiprange.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/005_version_skiprange.go new file mode 100644 index 0000000000..7c56236f64 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/005_version_skiprange.go @@ -0,0 +1,94 @@ +package migrations + +import ( + "context" + "database/sql" + + "github.com/sirupsen/logrus" +) + +const VersionSkipRangeMigrationKey = 5 +const SkipRangeAnnotationKey = "olm.skipRange" + +// Register this migration +func init() { + registerMigration(VersionSkipRangeMigrationKey, versionSkipRangeMigration) +} + +var versionSkipRangeMigration = &Migration{ + Id: VersionSkipRangeMigrationKey, + Up: func(ctx context.Context, tx *sql.Tx) error { + sql := ` + ALTER TABLE operatorbundle + ADD COLUMN skiprange TEXT; + + ALTER TABLE operatorbundle + ADD COLUMN version TEXT; + ` + _, err := tx.ExecContext(ctx, sql) + if err != nil { + return err + } + + bundles, err := listBundles(ctx, tx) + if err != nil { + return err + } + for _, bundle := range bundles { + if err := extractVersioning(ctx, tx, bundle); err != nil { + logrus.Warnf("error backfilling related images: %v", err) + continue + } + } + return err + }, + Down: func(ctx context.Context, tx *sql.Tx) error { + foreignKeyOff := `PRAGMA foreign_keys = 0` + createTempTable := `CREATE TABLE operatorbundle_backup (name TEXT, csv TEXT, bundle TEXT, bundlepath TEXT)` + backupTargetTable := `INSERT INTO operatorbundle_backup SELECT name, csv, bundle, bundlepath FROM operatorbundle` + dropTargetTable := `DROP TABLE operatorbundle` + renameBackUpTable := `ALTER TABLE operatorbundle_backup RENAME TO operatorbundle;` + foreignKeyOn := `PRAGMA foreign_keys = 1` + _, err := tx.ExecContext(ctx, foreignKeyOff) + if err != nil { + return err + } + _, err = tx.ExecContext(ctx, createTempTable) + if err != nil { + return err + } + _, err = tx.ExecContext(ctx, backupTargetTable) + if err != nil { + return err + } + _, err = tx.ExecContext(ctx, dropTargetTable) + if err != nil { + return err + } + _, err = tx.ExecContext(ctx, renameBackUpTable) + if err != nil { + return err + } + _, err = tx.ExecContext(ctx, foreignKeyOn) + return err + }, +} + +func extractVersioning(ctx context.Context, tx *sql.Tx, name string) error { + addSql := `insert into operatorbundle(version, skiprange) values(?,?)` + csv, err := getCSV(ctx, tx, name) + if err != nil { + logrus.Warnf("error backfilling versioning: %v", err) + return err + } + skiprange, ok := csv.Annotations[SkipRangeAnnotationKey] + if !ok { + skiprange = "" + } + version, err := csv.GetVersion() + if err != nil { + version = "" + } + _, err = tx.ExecContext(ctx, addSql, version, skiprange) + return err +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/migrations.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/migrations.go index d2802c2ee0..b9bb60fbaf 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/migrations.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrations/migrations.go @@ -3,6 +3,7 @@ package migrations import ( "context" "database/sql" + "fmt" "sort" ) @@ -80,3 +81,13 @@ func Only(key int) Migrations { func All() MigrationSet { return migrations } + +func registerMigration(key int, m *Migration) { + if _, ok := migrations[key]; ok { + panic(fmt.Sprintf("already have a migration registered with id %d", key)) + } + if m.Id != key { + panic(fmt.Sprintf("migration has wrong id for key. key: %d, id: %d", key, m.Id)) + } + migrations[key] = m +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrator.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrator.go index f1c349200b..da86bbc202 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrator.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/migrator.go @@ -69,9 +69,14 @@ func (m *SQLLiteMigrator) Up(ctx context.Context, migrations migrations.Migratio if err != nil { return err } + var commitErr error defer func() { + if commitErr == nil { + return + } + logrus.WithError(commitErr).Warningf("tx commit failed") if err := tx.Rollback(); err != nil { - logrus.WithError(err).Debugf("couldn't rollback - this is expected if the transaction committed") + logrus.WithError(err).Warningf("couldn't rollback after failed commit") } }() @@ -97,10 +102,8 @@ func (m *SQLLiteMigrator) Up(ctx context.Context, migrations migrations.Migratio return err } } - if err := tx.Commit(); err != nil { - return err - } - return nil + commitErr = tx.Commit() + return commitErr } func (m *SQLLiteMigrator) Down(ctx context.Context, migrations migrations.Migrations) error { @@ -108,9 +111,14 @@ func (m *SQLLiteMigrator) Down(ctx context.Context, migrations migrations.Migrat if err != nil { return err } + var commitErr error defer func() { + if commitErr == nil { + return + } + logrus.WithError(commitErr).Warningf("tx commit failed") if err := tx.Rollback(); err != nil { - logrus.WithError(err).Debugf("couldn't rollback - this is expected if the transaction committed") + logrus.WithError(err).Warningf("couldn't rollback after failed commit") } }() if err := m.ensureMigrationTable(ctx, tx); err != nil { @@ -135,10 +143,8 @@ func (m *SQLLiteMigrator) Down(ctx context.Context, migrations migrations.Migrat return err } } - if err := tx.Commit(); err != nil { - return err - } - return nil + commitErr = tx.Commit() + return commitErr } func (m *SQLLiteMigrator) ensureMigrationTable(ctx context.Context, tx *sql.Tx) error { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go index 54d3d95e53..0ebc4f6954 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/query.go @@ -36,6 +36,8 @@ func (s *SQLQuerier) ListTables(ctx context.Context) ([]string, error) { if err != nil { return nil, err } + defer rows.Close() + tables := []string{} for rows.Next() { var tableName sql.NullString @@ -56,6 +58,8 @@ func (s *SQLQuerier) ListPackages(ctx context.Context) ([]string, error) { if err != nil { return nil, err } + defer rows.Close() + packages := []string{} for rows.Next() { var pkgName sql.NullString @@ -77,6 +81,7 @@ func (s *SQLQuerier) GetPackage(ctx context.Context, name string) (*registry.Pac if err != nil { return nil, err } + defer rows.Close() var pkgName sql.NullString var defaultChannel sql.NullString @@ -109,13 +114,14 @@ func (s *SQLQuerier) GetPackage(ctx context.Context, name string) (*registry.Pac } func (s *SQLQuerier) GetBundle(ctx context.Context, pkgName, channelName, csvName string) (*api.Bundle, error) { - query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath + query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath, operatorbundle.version, operatorbundle.skiprange FROM operatorbundle INNER JOIN channel_entry ON operatorbundle.name=channel_entry.operatorbundle_name WHERE channel_entry.package_name=? AND channel_entry.channel_name=? AND operatorbundle_name=? LIMIT 1` rows, err := s.db.QueryContext(ctx, query, pkgName, channelName, csvName) if err != nil { return nil, err } + defer rows.Close() if !rows.Next() { return nil, fmt.Errorf("no entry found for %s %s %s", pkgName, channelName, csvName) @@ -124,7 +130,9 @@ func (s *SQLQuerier) GetBundle(ctx context.Context, pkgName, channelName, csvNam var name sql.NullString var bundle sql.NullString var bundlePath sql.NullString - if err := rows.Scan(&entryId, &name, &bundle, &bundlePath); err != nil { + var version sql.NullString + var skipRange sql.NullString + if err := rows.Scan(&entryId, &name, &bundle, &bundlePath, &version, &skipRange); err != nil { return nil, err } @@ -139,6 +147,8 @@ func (s *SQLQuerier) GetBundle(ctx context.Context, pkgName, channelName, csvNam out.PackageName = pkgName out.ChannelName = channelName out.BundlePath = bundlePath.String + out.Version = version.String + out.SkipRange = skipRange.String provided, required, err := s.GetApisForEntry(ctx, entryId.Int64) if err != nil { @@ -151,7 +161,7 @@ func (s *SQLQuerier) GetBundle(ctx context.Context, pkgName, channelName, csvNam } func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkgName string, channelName string) (*api.Bundle, error) { - query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath FROM channel + query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath, operatorbundle.version, operatorbundle.skiprange FROM channel INNER JOIN operatorbundle ON channel.head_operatorbundle_name=operatorbundle.name INNER JOIN channel_entry ON (channel_entry.channel_name = channel.name and channel_entry.package_name=channel.package_name and channel_entry.operatorbundle_name=operatorbundle.name) WHERE channel.package_name=? AND channel.name=? LIMIT 1` @@ -159,6 +169,7 @@ func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkgName string, ch if err != nil { return nil, err } + defer rows.Close() if !rows.Next() { return nil, fmt.Errorf("no entry found for %s %s", pkgName, channelName) @@ -167,7 +178,9 @@ func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkgName string, ch var name sql.NullString var bundle sql.NullString var bundlePath sql.NullString - if err := rows.Scan(&entryId, &name, &bundle, &bundlePath); err != nil { + var version sql.NullString + var skipRange sql.NullString + if err := rows.Scan(&entryId, &name, &bundle, &bundlePath, &version, &skipRange); err != nil { return nil, err } @@ -182,6 +195,8 @@ func (s *SQLQuerier) GetBundleForChannel(ctx context.Context, pkgName string, ch out.PackageName = pkgName out.ChannelName = channelName out.BundlePath = bundlePath.String + out.Version = version.String + out.SkipRange = skipRange.String provided, required, err := s.GetApisForEntry(ctx, entryId.Int64) if err != nil { @@ -202,6 +217,7 @@ func (s *SQLQuerier) GetChannelEntriesThatReplace(ctx context.Context, name stri if err != nil { return } + defer rows.Close() entries = []*registry.ChannelEntry{} @@ -228,7 +244,7 @@ func (s *SQLQuerier) GetChannelEntriesThatReplace(ctx context.Context, name stri } func (s *SQLQuerier) GetBundleThatReplaces(ctx context.Context, name, pkgName, channelName string) (*api.Bundle, error) { - query := `SELECT DISTINCT replaces.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath + query := `SELECT DISTINCT replaces.entry_id, operatorbundle.name, operatorbundle.bundle, operatorbundle.bundlepath, operatorbundle.version, operatorbundle.skiprange FROM channel_entry LEFT OUTER JOIN channel_entry replaces ON replaces.replaces = channel_entry.entry_id INNER JOIN operatorbundle ON replaces.operatorbundle_name = operatorbundle.name @@ -237,6 +253,8 @@ func (s *SQLQuerier) GetBundleThatReplaces(ctx context.Context, name, pkgName, c if err != nil { return nil, err } + defer rows.Close() + if !rows.Next() { return nil, fmt.Errorf("no entry found for %s %s", pkgName, channelName) @@ -245,7 +263,9 @@ func (s *SQLQuerier) GetBundleThatReplaces(ctx context.Context, name, pkgName, c var outName sql.NullString var bundle sql.NullString var bundlePath sql.NullString - if err := rows.Scan(&entryId, &outName, &bundle, &bundlePath); err != nil { + var version sql.NullString + var skipRange sql.NullString + if err := rows.Scan(&entryId, &outName, &bundle, &bundlePath, &version, &skipRange); err != nil { return nil, err } @@ -260,6 +280,8 @@ func (s *SQLQuerier) GetBundleThatReplaces(ctx context.Context, name, pkgName, c out.PackageName = pkgName out.ChannelName = channelName out.BundlePath = bundlePath.String + out.Version = version.String + out.SkipRange = skipRange.String provided, required, err := s.GetApisForEntry(ctx, entryId.Int64) if err != nil { @@ -282,6 +304,7 @@ func (s *SQLQuerier) GetChannelEntriesThatProvide(ctx context.Context, group, ve if err != nil { return } + defer rows.Close() entries = []*registry.ChannelEntry{} @@ -320,6 +343,7 @@ func (s *SQLQuerier) GetLatestChannelEntriesThatProvide(ctx context.Context, gro if err != nil { return nil, err } + defer rows.Close() entries = []*registry.ChannelEntry{} @@ -348,8 +372,8 @@ func (s *SQLQuerier) GetLatestChannelEntriesThatProvide(ctx context.Context, gro } // Get the the latest bundle that provides the API in a default channel, error unless there is ONLY one -func (s *SQLQuerier) GetBundleThatProvides(ctx context.Context, group, version, kind string) (*api.Bundle, error) { - query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.bundle, operatorbundle.bundlepath, MIN(channel_entry.depth), channel_entry.operatorbundle_name, channel_entry.package_name, channel_entry.channel_name, channel_entry.replaces +func (s *SQLQuerier) GetBundleThatProvides(ctx context.Context, group, apiVersion, kind string) (*api.Bundle, error) { + query := `SELECT DISTINCT channel_entry.entry_id, operatorbundle.bundle, operatorbundle.bundlepath, MIN(channel_entry.depth), channel_entry.operatorbundle_name, channel_entry.package_name, channel_entry.channel_name, channel_entry.replaces, operatorbundle.version, operatorbundle.skiprange FROM channel_entry INNER JOIN api_provider ON channel_entry.entry_id = api_provider.channel_entry_id INNER JOIN operatorbundle ON operatorbundle.name = channel_entry.operatorbundle_name @@ -357,13 +381,14 @@ func (s *SQLQuerier) GetBundleThatProvides(ctx context.Context, group, version, WHERE api_provider.group_name = ? AND api_provider.version = ? AND api_provider.kind = ? AND package.default_channel = channel_entry.channel_name GROUP BY channel_entry.package_name, channel_entry.channel_name` - rows, err := s.db.QueryContext(ctx, query, group, version, kind) + rows, err := s.db.QueryContext(ctx, query, group, apiVersion, kind) if err != nil { return nil, err } + defer rows.Close() if !rows.Next() { - return nil, fmt.Errorf("no entry found that provides %s %s %s", group, version, kind) + return nil, fmt.Errorf("no entry found that provides %s %s %s", group, apiVersion, kind) } var entryId sql.NullInt64 var bundle sql.NullString @@ -373,12 +398,14 @@ func (s *SQLQuerier) GetBundleThatProvides(ctx context.Context, group, version, var pkgName sql.NullString var channelName sql.NullString var replaces sql.NullString - if err := rows.Scan(&entryId, &bundle, &bundlePath, &min_depth, &bundleName, &pkgName, &channelName, &replaces); err != nil { + var version sql.NullString + var skipRange sql.NullString + if err := rows.Scan(&entryId, &bundle, &bundlePath, &min_depth, &bundleName, &pkgName, &channelName, &replaces, &version, &skipRange); err != nil { return nil, err } if !bundle.Valid { - return nil, fmt.Errorf("no entry found that provides %s %s %s", group, version, kind) + return nil, fmt.Errorf("no entry found that provides %s %s %s", group, apiVersion, kind) } out := &api.Bundle{} @@ -392,6 +419,8 @@ func (s *SQLQuerier) GetBundleThatProvides(ctx context.Context, group, version, out.PackageName = pkgName.String out.ChannelName = channelName.String out.BundlePath = bundlePath.String + out.Version = version.String + out.SkipRange = skipRange.String provided, required, err := s.GetApisForEntry(ctx, entryId.Int64) if err != nil { @@ -409,6 +438,8 @@ func (s *SQLQuerier) ListImages(ctx context.Context) ([]string, error) { if err != nil { return nil, err } + defer rows.Close() + images := []string{} for rows.Next() { var imgName sql.NullString @@ -428,6 +459,7 @@ func (s *SQLQuerier) GetImagesForBundle(ctx context.Context, csvName string) ([] if err != nil { return nil, err } + defer rows.Close() images := []string{} for rows.Next() { var imgName sql.NullString @@ -450,6 +482,7 @@ func (s *SQLQuerier) GetApisForEntry(ctx context.Context, entryId int64) (provid if err != nil { return nil,nil, err } + provided = []*api.GroupVersionKind{} for providedRows.Next() { var groupName sql.NullString @@ -470,6 +503,9 @@ func (s *SQLQuerier) GetApisForEntry(ctx context.Context, entryId int64) (provid Plural: pluralName.String, }) } + if err := providedRows.Close(); err != nil { + return nil, nil, err + } requiredQuery := `SELECT DISTINCT api.group_name, api.version, api.kind, api.plural FROM api INNER JOIN api_requirer ON (api.group_name=api_requirer.group_name AND api.version=api_requirer.version AND api.kind=api_requirer.kind) @@ -499,6 +535,9 @@ func (s *SQLQuerier) GetApisForEntry(ctx context.Context, entryId int64) (provid Plural: pluralName.String, }) } + if err := requiredRows.Close(); err != nil { + return nil, nil, err + } return } diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/remove.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/remove.go new file mode 100644 index 0000000000..644950adeb --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/remove.go @@ -0,0 +1,67 @@ +package sqlite + +import ( + "fmt" + "strings" + + "github.com/sirupsen/logrus" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + + "github.com/operator-framework/operator-registry/pkg/registry" +) + +type SQLRemover interface { + Remove() error +} + +// PackageRemover removes a package from the database +type PackageRemover struct { + store registry.Load + packages string +} + +var _ SQLRemover = &PackageRemover{} + +func NewSQLRemoverForPackages(store registry.Load, packages string) *PackageRemover { + return &PackageRemover{ + store: store, + packages: packages, + } +} + +func (d *PackageRemover) Remove() error { + log := logrus.WithField("pkg", d.packages) + + log.Info("deleting packages") + + var errs []error + packages := sanitizePackageList(strings.Split(d.packages, ",")) + log.Info("input has been sanitized") + log.Infof("packages: %s", packages) + + for _, pkg := range packages { + if err := d.store.RmPackageName(pkg); err != nil { + errs = append(errs, fmt.Errorf("error removing operator package %s: %s", pkg, err)) + } + } + + return utilerrors.NewAggregate(errs) +} + +// sanitizePackageList sanitizes the set of package(s) specified. It removes +// duplicates and ignores empty string. +func sanitizePackageList(in []string) []string { + out := make([]string, 0) + + inMap := map[string]bool{} + for _, item := range in { + if _, ok := inMap[item]; ok || item == "" { + continue + } + + inMap[item] = true + out = append(out, item) + } + + return out +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cee85d7b2b..c66ca71018 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -156,10 +156,11 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 -# github.com/operator-framework/operator-registry v1.5.1 +# github.com/operator-framework/operator-registry v1.5.3 github.com/operator-framework/operator-registry/pkg/api github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1 github.com/operator-framework/operator-registry/pkg/client +github.com/operator-framework/operator-registry/pkg/containertools github.com/operator-framework/operator-registry/pkg/registry github.com/operator-framework/operator-registry/pkg/server github.com/operator-framework/operator-registry/pkg/sqlite From 4b1c5a8a86d270592a76b1fdbdb157572f319951 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Sat, 2 Nov 2019 11:35:26 -0400 Subject: [PATCH 02/12] chore(chart): switch to temporary configmap server image images in quay are incorrect, and quay is readonly --- deploy/chart/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/chart/values.yaml b/deploy/chart/values.yaml index 8bbedfb89d..91b6dc0e0c 100644 --- a/deploy/chart/values.yaml +++ b/deploy/chart/values.yaml @@ -25,7 +25,7 @@ olm: catalog: replicaCount: 1 - commandArgs: -configmapServerImage=quay.io/operator-framework/configmap-operator-registry:latest + commandArgs: -configmapServerImage=ecordell/configmap-operator-registry:latest image: ref: quay.io/operator-framework/olm:master pullPolicy: Always From af7b6d1a6ada1e9bf39666ea16e8187839f23895 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Sat, 2 Nov 2019 12:51:01 -0400 Subject: [PATCH 03/12] feat(operator): remove another location that parses csvs --- pkg/controller/registry/resolver/operators.go | 20 +++++-------------- .../registry/resolver/operators_test.go | 8 +++++--- pkg/controller/registry/resolver/util_test.go | 1 + 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/pkg/controller/registry/resolver/operators.go b/pkg/controller/registry/resolver/operators.go index 203b8043c1..aa76b7ddfc 100644 --- a/pkg/controller/registry/resolver/operators.go +++ b/pkg/controller/registry/resolver/operators.go @@ -1,7 +1,6 @@ package resolver import ( - "encoding/json" "fmt" "hash/fnv" "sort" @@ -239,19 +238,10 @@ type Operator struct { var _ OperatorSurface = &Operator{} func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey CatalogKey) (*Operator, error) { - if bundle.CsvJson == "" { - return nil, fmt.Errorf("no csv json found") - } - csv := ®istry.ClusterServiceVersion{} - if err := json.Unmarshal([]byte(bundle.CsvJson), csv); err != nil { - return nil, err - } - - version, _ := csv.GetVersion() - parsedVersion, err := semver.ParseTolerant(version) - v := &parsedVersion + parsedVersion, err := semver.ParseTolerant(bundle.Version) + version := &parsedVersion if err != nil { - v = nil + version = nil } provided := APISet{} @@ -264,8 +254,8 @@ func NewOperatorFromBundle(bundle *api.Bundle, startingCSV string, sourceKey Cat } return &Operator{ - name: csv.GetName(), - version: v, + name: bundle.CsvName, + version: version, providedAPIs: provided, requiredAPIs: required, bundle: bundle, diff --git a/pkg/controller/registry/resolver/operators_test.go b/pkg/controller/registry/resolver/operators_test.go index c0adf29174..23dd5175d5 100644 --- a/pkg/controller/registry/resolver/operators_test.go +++ b/pkg/controller/registry/resolver/operators_test.go @@ -917,6 +917,7 @@ func TestNewOperatorFromBundle(t *testing.T) { CsvName: "testBundle", PackageName: "testPackage", ChannelName: "testChannel", + Version: version.String(), CsvJson: string(csvJson), Object: []string{string(csvJson)}, } @@ -987,6 +988,7 @@ func TestNewOperatorFromBundle(t *testing.T) { CsvName: "testBundle", PackageName: "testPackage", ChannelName: "testChannel", + Version: version.String(), CsvJson: string(csvJsonWithApis), Object: []string{string(csvJsonWithApis), string(crdJson)}, ProvidedApis: []*api.GroupVersionKind{ @@ -1038,7 +1040,7 @@ func TestNewOperatorFromBundle(t *testing.T) { replaces: "", }, want: &Operator{ - name: "testCSV", + name: "testBundle", version: &version.Version, providedAPIs: EmptyAPISet(), requiredAPIs: EmptyAPISet(), @@ -1058,7 +1060,7 @@ func TestNewOperatorFromBundle(t *testing.T) { replaces: "", }, want: &Operator{ - name: "testCSV", + name: "testBundle", version: &version.Version, providedAPIs: APISet{ opregistry.APIKey{ @@ -1104,7 +1106,7 @@ func TestNewOperatorFromBundle(t *testing.T) { replaces: "replaced", }, want: &Operator{ - name: "testCSV", + name: "testBundle", providedAPIs: EmptyAPISet(), requiredAPIs: EmptyAPISet(), bundle: bundleNoAPIs, diff --git a/pkg/controller/registry/resolver/util_test.go b/pkg/controller/registry/resolver/util_test.go index aa6b3569d3..1ce57ae92d 100644 --- a/pkg/controller/registry/resolver/util_test.go +++ b/pkg/controller/registry/resolver/util_test.go @@ -258,6 +258,7 @@ func bundle(name, pkg, channel, replaces string, providedCRDs, requiredCRDs, pro ChannelName: channel, CsvJson: string(csvJson), Object: objs, + Version: "0.0.0", ProvidedApis: apiSetToGVk(providedCRDs, providedAPIServices), RequiredApis: apiSetToGVk(requiredCRDs, requiredAPIServices), } From f43529b9f3b9f6dc599b8b0f701f875f97bdd708 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Sat, 2 Nov 2019 12:04:26 -0400 Subject: [PATCH 04/12] chore(modules): import configmap code from operator-registry --- .../pkg/configmap/configmap.go | 149 ++++++++++ .../pkg/configmap/configmap_writer.go | 222 +++++++++++++++ .../operator-registry/pkg/lib/bundle/build.go | 75 +++++ .../pkg/lib/bundle/generate.go | 267 ++++++++++++++++++ vendor/modules.txt | 5 + 5 files changed, 718 insertions(+) create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/build.go create mode 100644 vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go new file mode 100644 index 0000000000..9400bcf6eb --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go @@ -0,0 +1,149 @@ +package configmap + +import ( + "errors" + "fmt" + libbundle "github.com/operator-framework/operator-registry/pkg/lib/bundle" + "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + "strings" +) + +func NewBundleLoader() *BundleLoader { + logger := logrus.NewEntry(logrus.New()) + return NewBundleLoaderWithLogger(logger) +} + +func NewBundleLoaderWithLogger(logger *logrus.Entry) *BundleLoader { + return &BundleLoader{ + logger: logger, + } +} + +// Manifest contains a bundle and a PackageManifest. +type Manifest struct { + Bundle *registry.Bundle + PackageManifest *registry.PackageManifest +} + +type BundleLoader struct { + logger *logrus.Entry +} + +// Load accepts a ConfigMap object, iterates through the Data section and +// creates an operator registry Bundle object. +// If the Data section has a PackageManifest resource then it is also +// deserialized and included in the result. +func (l *BundleLoader) Load(cm *corev1.ConfigMap) (manifest *Manifest, err error) { + if cm == nil { + err = errors.New("ConfigMap must not be ") + return + } + + logger := l.logger.WithFields(logrus.Fields{ + "configmap": fmt.Sprintf("%s/%s", cm.GetNamespace(), cm.GetName()), + }) + + bundle, _, bundleErr := loadBundle(logger, cm.Data) + if bundleErr != nil { + err = fmt.Errorf("failed to extract bundle from configmap - %v", bundleErr) + return + } + + // get package manifest information from required annotations + annotations := cm.GetAnnotations() + if len(annotations) == 0 { + err = fmt.Errorf("missing required annoations on configmap %v", cm.GetName()) + return + } + + switch mediatype := annotations[libbundle.MediatypeLabel]; mediatype { + case "registry+v1": + // supported, proceed + default: + err = fmt.Errorf("failed to parse annotations due to unsupported media type %v", mediatype) + return + } + + var packageChannels []registry.PackageChannel + channels := strings.Split(annotations[libbundle.ChannelsLabel], ",") + for _, channel := range channels { + packageChannels = append(packageChannels, registry.PackageChannel{ + Name: channel, + }) + } + + manifest = &Manifest{ + Bundle: bundle, + PackageManifest: ®istry.PackageManifest{ + PackageName: annotations[libbundle.PackageLabel], + Channels: packageChannels, + DefaultChannelName: annotations[libbundle.ChannelDefaultLabel], + }, + } + return +} + +func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *registry.Bundle, skipped map[string]string, err error) { + bundle = ®istry.Bundle{} + skipped = map[string]string{} + + // Add kube resources to the bundle. + for name, content := range data { + reader := strings.NewReader(content) + logger := entry.WithFields(logrus.Fields{ + "key": name, + }) + + resource, decodeErr := registry.DecodeUnstructured(reader) + if decodeErr != nil { + logger.Infof("skipping due to decode error - %v", decodeErr) + + // It may not be not a kube resource, let's add it to the skipped + // list so the caller can act on ot. + skipped[name] = content + continue + } + + // It's a valid kube resource, + // could be a crd, csv or other raw kube manifest(s). + bundle.Add(resource) + logger.Infof("added to bundle, Kind=%s", resource.GetKind()) + } + + return +} + +func loadPackageManifest(entry *logrus.Entry, resources map[string]string) *registry.PackageManifest { + // Let's inspect if any of the skipped non kube resources is a PackageManifest type. + // The first one we run into will be selected. + for name, content := range resources { + logger := entry.WithFields(logrus.Fields{ + "key": name, + }) + + // Is it a package yaml file? + reader := strings.NewReader(content) + packageManifest, decodeErr := registry.DecodePackageManifest(reader) + if decodeErr != nil { + logger.Infof("skipping, not a PackageManifest type - %v", decodeErr) + continue + } + + logger.Infof("found a PackageManifest type resource - packageName=%s", packageManifest.PackageName) + + return packageManifest + } + + return nil +} + +func extract(data map[string]string) []string { + resources := make([]string, 0) + for _, v := range data { + resources = append(resources, v) + } + + return resources +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go new file mode 100644 index 0000000000..9a3a2f511b --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go @@ -0,0 +1,222 @@ +package configmap + +import ( + "fmt" + "io/ioutil" + "os" + "regexp" + + "github.com/ghodss/yaml" + _ "github.com/mattn/go-sqlite3" + "github.com/sirupsen/logrus" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + "github.com/operator-framework/operator-registry/pkg/client" + "github.com/operator-framework/operator-registry/pkg/lib/bundle" +) + +// configmap keys can contain underscores, but configmap names can not +var unallowedKeyChars = regexp.MustCompile("[^-A-Za-z0-9_.]") + +const ( + EnvContainerImage = "CONTAINER_IMAGE" + ConfigMapImageAnnotationKey = "olm.sourceImage" +) + +type AnnotationsFile struct { + Annotations struct { + Resources string `json:"operators.operatorframework.io.bundle.manifests.v1"` + MediaType string `json:"operators.operatorframework.io.bundle.mediatype.v1"` + Metadata string `json:"operators.operatorframework.io.bundle.metadata.v1"` + Package string `json:"operators.operatorframework.io.bundle.package.v1"` + Channels string `json:"operators.operatorframework.io.bundle.channels.v1"` + ChannelDefault string `json:"operators.operatorframework.io.bundle.channel.default.v1"` + } `json:"annotations"` +} + +type ConfigMapWriter struct { + manifestsDir string + configMapName string + namespace string + clientset *kubernetes.Clientset +} + +func NewConfigMapLoaderForDirectory(configMapName, namespace, manifestsDir, kubeconfig string) *ConfigMapWriter { + clientset, err := client.NewKubeClient(kubeconfig, logrus.StandardLogger()) + if err != nil { + logrus.Fatalf("cluster config failed: %v", err) + } + + return &ConfigMapWriter{ + manifestsDir: manifestsDir, + configMapName: configMapName, + namespace: namespace, + clientset: clientset, + } +} + +func TranslateInvalidChars(input string) string { + validConfigMapKey := unallowedKeyChars.ReplaceAllString(input, "~") + return validConfigMapKey +} + +func (c *ConfigMapWriter) Populate(maxDataSizeLimit uint64) error { + subDirs := []string{"manifests/", "metadata/"} + + configMapPopulate, err := c.clientset.CoreV1().ConfigMaps(c.namespace).Get(c.configMapName, metav1.GetOptions{}) + if err != nil { + return err + } + configMapPopulate.Data = map[string]string{} + + var totalSize uint64 + for _, dir := range subDirs { + completePath := c.manifestsDir + dir + files, err := ioutil.ReadDir(completePath) + if err != nil { + logrus.Errorf("read dir failed: %v", err) + return err + } + + for _, file := range files { + log := logrus.WithField("file", completePath+file.Name()) + log.Info("Reading file") + content, err := ioutil.ReadFile(completePath + file.Name()) + if err != nil { + log.Errorf("read failed: %v", err) + return err + } + totalSize += uint64(len(content)) + if totalSize > maxDataSizeLimit { + log.Errorf("File with size %v exceeded %v limit, aboring", len(content), maxDataSizeLimit) + return fmt.Errorf("file %v bigger than total allowed limit", file.Name()) + } + + validConfigMapKey := TranslateInvalidChars(file.Name()) + if validConfigMapKey != file.Name() { + logrus.WithFields(logrus.Fields{ + "file.Name": file.Name(), + "validConfigMapKey": validConfigMapKey, + }).Info("translated filename for configmap comptability") + } + if file.Name() == bundle.AnnotationsFile { + var annotationsFile AnnotationsFile + err := yaml.Unmarshal(content, &annotationsFile) + if err != nil { + return err + } + configMapPopulate.SetAnnotations(map[string]string{ + bundle.ManifestsLabel: annotationsFile.Annotations.Resources, + bundle.MediatypeLabel: annotationsFile.Annotations.MediaType, + bundle.MetadataLabel: annotationsFile.Annotations.Metadata, + bundle.PackageLabel: annotationsFile.Annotations.Package, + bundle.ChannelsLabel: annotationsFile.Annotations.Channels, + bundle.ChannelDefaultLabel: annotationsFile.Annotations.ChannelDefault, + }) + } else { + configMapPopulate.Data[validConfigMapKey] = string(content) + } + } + } + + if sourceImage := os.Getenv(EnvContainerImage); sourceImage != "" { + annotations := configMapPopulate.GetAnnotations() + annotations[ConfigMapImageAnnotationKey] = sourceImage + } + + _, err = c.clientset.CoreV1().ConfigMaps(c.namespace).Update(configMapPopulate) + if err != nil { + return err + } + return nil +} + +// LaunchBundleImage will launch a bundle image and also create a configmap for +// storing the data that will be updated to contain the bundle image data. It is +// the responsibility of the caller to delete the job, the pod, and the configmap +// when done. This function is intended to be called from OLM, but is put here +// for locality. +func LaunchBundleImage(kubeclient kubernetes.Interface, bundleImage, initImage, namespace string) (*corev1.ConfigMap, *batchv1.Job, error) { + // create configmap for bundle image data to write to (will be returned) + newConfigMap, err := kubeclient.CoreV1().ConfigMaps(namespace).Create(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "bundle-image-", + }, + }) + if err != nil { + return nil, nil, err + } + + launchJob := batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "deploy-bundle-image-", + }, + Spec: batchv1.JobSpec{ + //ttlSecondsAfterFinished: 0 // can use in the future to not have to clean up job + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bundle-image", + }, + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyOnFailure, + Containers: []corev1.Container{ + { + Name: "bundle-image", + Image: bundleImage, + ImagePullPolicy: "Never", + Command: []string{"/injected/opm", "alpha", "bundle", "extract", "-n", namespace, "-c", newConfigMap.GetName()}, + Env: []corev1.EnvVar{ + { + Name: EnvContainerImage, + Value: bundleImage, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "copydir", + MountPath: "/injected", + }, + }, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "copy-binary", + Image: initImage, + ImagePullPolicy: "Never", + Command: []string{"/bin/cp", "opm", "/copy-dest"}, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "copydir", + MountPath: "/copy-dest", + }, + }, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "copydir", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + }, + }, + }, + } + launchedJob, err := kubeclient.BatchV1().Jobs(namespace).Create(&launchJob) + if err != nil { + err := kubeclient.CoreV1().ConfigMaps(namespace).Delete(newConfigMap.GetName(), &metav1.DeleteOptions{}) + if err != nil { + // already in an error, so just report it + logrus.Errorf("failed to remove configmap: %v", err) + } + return nil, nil, err + } + + return newConfigMap, launchedJob, nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/build.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/build.go new file mode 100644 index 0000000000..a121581fcc --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/build.go @@ -0,0 +1,75 @@ +package bundle + +import ( + "fmt" + "os" + "os/exec" + "path" + + log "github.com/sirupsen/logrus" +) + +// Create build command to build bundle manifests image +func BuildBundleImage(directory, imageTag, imageBuilder string) (*exec.Cmd, error) { + var args []string + + dockerfilePath := path.Join(directory, DockerFile) + + switch imageBuilder { + case "docker", "podman": + args = append(args, "build", "-f", dockerfilePath, "-t", imageTag, ".") + case "buildah": + args = append(args, "bud", "--format=docker", "-f", dockerfilePath, "-t", imageTag, ".") + default: + return nil, fmt.Errorf("%s is not supported image builder", imageBuilder) + } + + return exec.Command(imageBuilder, args...), nil +} + +func ExecuteCommand(cmd *exec.Cmd) error { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + log.Debugf("Running %#v", cmd.Args) + + if err := cmd.Run(); err != nil { + return fmt.Errorf("Failed to exec %#v: %v", cmd.Args, err) + } + + return nil +} + +// BuildFunc is used to build bundle container image from a list of manifests +// that exist in local directory and it also generates Dockerfile annotations.yaml +// which contains media type, package name and channels information if the file +// doesn't exist locally. +// Inputs: +// @directory: The local directory where bundle manifests and metadata are located +// @imageTag: The image tag that is applied to the bundle image +// @imageBuilder: The image builder tool that is used to build container image +// (docker, buildah or podman) +// @packageName: The name of the package that bundle image belongs to +// @channels: The list of channels that bundle image belongs to +// @channelDefault: The default channel for the bundle image +// @overwrite: Boolean flag to enable overwriting annotations.yaml locally if existed +func BuildFunc(directory, imageTag, imageBuilder, packageName, channels, channelDefault string, overwrite bool) error { + // Generate annotations.yaml and Dockerfile + err := GenerateFunc(directory, packageName, channels, channelDefault, overwrite) + if err != nil { + return err + } + + // Build bundle image + log.Info("Building bundle image") + buildCmd, err := BuildBundleImage(path.Clean(directory), imageTag, imageBuilder) + if err != nil { + return err + } + + if err := ExecuteCommand(buildCmd); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go new file mode 100644 index 0000000000..d22e17c93b --- /dev/null +++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go @@ -0,0 +1,267 @@ +package bundle + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + "gopkg.in/yaml.v2" +) + +const ( + DefaultPermission = 0644 + RegistryV1Type = "registry+v1" + PlainType = "plain" + HelmType = "helm" + AnnotationsFile = "annotations.yaml" + DockerFile = "Dockerfile" + ManifestsDir = "manifests/" + MetadataDir = "metadata/" + ManifestsLabel = "operators.operatorframework.io.bundle.manifests.v1" + MetadataLabel = "operators.operatorframework.io.bundle.metadata.v1" + MediatypeLabel = "operators.operatorframework.io.bundle.mediatype.v1" + PackageLabel = "operators.operatorframework.io.bundle.package.v1" + ChannelsLabel = "operators.operatorframework.io.bundle.channels.v1" + ChannelDefaultLabel = "operators.operatorframework.io.bundle.channel.default.v1" +) + +type AnnotationMetadata struct { + Annotations map[string]string `yaml:"annotations"` +} + +// GenerateFunc builds annotations.yaml with mediatype, manifests & +// metadata directories in bundle image, package name, channels and default +// channels information and then writes the file to `/metadata` directory. +// Inputs: +// @directory: The local directory where bundle manifests and metadata are located +// @packageName: The name of the package that bundle image belongs to +// @channels: The list of channels that bundle image belongs to +// @channelDefault: The default channel for the bundle image +// @overwrite: Boolean flag to enable overwriting annotations.yaml locally if existed +func GenerateFunc(directory, packageName, channels, channelDefault string, overwrite bool) error { + var mediaType string + + // Determine mediaType + mediaType, err := GetMediaType(directory) + if err != nil { + return err + } + + log.Info("Building annotations.yaml") + + // Generate annotations.yaml + content, err := GenerateAnnotations(mediaType, ManifestsDir, MetadataDir, packageName, channels, channelDefault) + if err != nil { + return err + } + + file, err := ioutil.ReadFile(filepath.Join(directory, MetadataDir, AnnotationsFile)) + if os.IsNotExist(err) || overwrite { + err = WriteFile(AnnotationsFile, filepath.Join(directory, MetadataDir), content) + if err != nil { + return err + } + } else if err != nil { + return err + } else { + log.Info("An annotations.yaml already exists in directory") + if err = ValidateAnnotations(file, content); err != nil { + return err + } + } + + log.Info("Building Dockerfile") + + // Generate Dockerfile + content, err = GenerateDockerfile(directory, mediaType, ManifestsDir, MetadataDir, packageName, channels, channelDefault) + if err != nil { + return err + } + + err = WriteFile(DockerFile, directory, content) + if err != nil { + return err + } + + return nil +} + +// GenerateFunc determines mediatype from files (yaml) in given directory +// Currently able to detect helm chart, registry+v1 (CSV) and plain k8s resources +// such as CRD. +func GetMediaType(directory string) (string, error) { + var files []string + + // Read all file names in directory + items, _ := ioutil.ReadDir(directory) + for _, item := range items { + if item.IsDir() { + continue + } else { + files = append(files, item.Name()) + } + } + + if len(files) == 0 { + return "", fmt.Errorf("The directory %s contains no files", directory) + } + + // Validate the file names to determine media type + for _, file := range files { + if file == "Chart.yaml" { + return HelmType, nil + } else if strings.HasSuffix(file, "clusterserviceversion.yaml") { + return RegistryV1Type, nil + } else { + continue + } + } + + return PlainType, nil +} + +// ValidateAnnotations validates existing annotations.yaml against generated +// annotations.yaml to ensure existing annotations.yaml contains expected values. +func ValidateAnnotations(existing, expected []byte) error { + var fileAnnotations AnnotationMetadata + var expectedAnnotations AnnotationMetadata + + log.Info("Validating existing annotations.yaml") + + err := yaml.Unmarshal(existing, &fileAnnotations) + if err != nil { + log.Errorf("Unable to parse existing annotations.yaml") + return err + } + + err = yaml.Unmarshal(expected, &expectedAnnotations) + if err != nil { + log.Errorf("Unable to parse expected annotations.yaml") + return err + } + + if len(fileAnnotations.Annotations) != len(expectedAnnotations.Annotations) { + return fmt.Errorf("Unmatched number of fields. Expected (%d) vs existing (%d)", + len(expectedAnnotations.Annotations), len(fileAnnotations.Annotations)) + } + + for label, item := range expectedAnnotations.Annotations { + value, ok := fileAnnotations.Annotations[label] + if ok == false { + return fmt.Errorf("Missing field: %s", label) + } + + if item != value { + return fmt.Errorf(`Expect field "%s" to have value "%s" instead of "%s"`, + label, item, value) + } + } + + return nil +} + +// ValidateAnnotations validates provided default channel to ensure it exists in +// provided channel list. +func ValidateChannelDefault(channels, channelDefault string) (string, error) { + var chanDefault string + var chanErr error + channelList := strings.Split(channels, ",") + + if channelDefault != "" { + for _, channel := range channelList { + if channel == channelDefault { + chanDefault = channelDefault + break + } + } + if chanDefault == "" { + chanDefault = channelList[0] + chanErr = fmt.Errorf(`The channel list "%s" doesn't contain channelDefault "%s"`, channels, channelDefault) + } + } else { + chanDefault = channelList[0] + } + + if chanDefault != "" { + return chanDefault, chanErr + } else { + return chanDefault, fmt.Errorf("Invalid channels is provied: %s", channels) + } +} + +// GenerateAnnotations builds annotations.yaml with mediatype, manifests & +// metadata directories in bundle image, package name, channels and default +// channels information. +func GenerateAnnotations(mediaType, manifests, metadata, packageName, channels, channelDefault string) ([]byte, error) { + annotations := &AnnotationMetadata{ + Annotations: map[string]string{ + MediatypeLabel: mediaType, + ManifestsLabel: manifests, + MetadataLabel: metadata, + PackageLabel: packageName, + ChannelsLabel: channels, + ChannelDefaultLabel: channelDefault, + }, + } + + chanDefault, err := ValidateChannelDefault(channels, channelDefault) + if err != nil { + return nil, err + } + + annotations.Annotations[ChannelDefaultLabel] = chanDefault + + afile, err := yaml.Marshal(annotations) + if err != nil { + return nil, err + } + + return afile, nil +} + +// GenerateDockerfile builds Dockerfile with mediatype, manifests & +// metadata directories in bundle image, package name, channels and default +// channels information in LABEL section. +func GenerateDockerfile(directory, mediaType, manifests, metadata, packageName, channels, channelDefault string) ([]byte, error) { + var fileContent string + + chanDefault, err := ValidateChannelDefault(channels, channelDefault) + if err != nil { + return nil, err + } + + // FROM + fileContent += "FROM scratch\n\n" + + // LABEL + fileContent += fmt.Sprintf("LABEL %s=%s\n", MediatypeLabel, mediaType) + fileContent += fmt.Sprintf("LABEL %s=%s\n", ManifestsLabel, manifests) + fileContent += fmt.Sprintf("LABEL %s=%s\n", MetadataLabel, metadata) + fileContent += fmt.Sprintf("LABEL %s=%s\n", PackageLabel, packageName) + fileContent += fmt.Sprintf("LABEL %s=%s\n", ChannelsLabel, channels) + fileContent += fmt.Sprintf("LABEL %s=%s\n\n", ChannelDefaultLabel, chanDefault) + + // CONTENT + fileContent += fmt.Sprintf("ADD %s %s\n", filepath.Join(directory, "*.yaml"), "/manifests/") + fileContent += fmt.Sprintf("ADD %s %s%s\n", filepath.Join(directory, metadata, AnnotationsFile), "/metadata/", AnnotationsFile) + + return []byte(fileContent), nil +} + +// Write `fileName` file with `content` into a `directory` +// Note: Will overwrite the existing `fileName` file if it exists +func WriteFile(fileName, directory string, content []byte) error { + if _, err := os.Stat(directory); os.IsNotExist(err) { + os.Mkdir(directory, os.ModePerm) + } + + err := ioutil.WriteFile(filepath.Join(directory, fileName), content, DefaultPermission) + if err != nil { + return err + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c66ca71018..ac680abe99 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -160,7 +160,12 @@ github.com/openshift/client-go/config/listers/config/v1 github.com/operator-framework/operator-registry/pkg/api github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1 github.com/operator-framework/operator-registry/pkg/client +<<<<<<< ours github.com/operator-framework/operator-registry/pkg/containertools +======= +github.com/operator-framework/operator-registry/pkg/configmap +github.com/operator-framework/operator-registry/pkg/lib/bundle +>>>>>>> theirs github.com/operator-framework/operator-registry/pkg/registry github.com/operator-framework/operator-registry/pkg/server github.com/operator-framework/operator-registry/pkg/sqlite From 2daed1dd2120fa3673874d6e4b9fc7b66b6c2796 Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Fri, 18 Oct 2019 15:00:38 -0400 Subject: [PATCH 05/12] WIP: extract bundle data and put in installplan --- .../operators/v1alpha1/installplan_types.go | 17 +++++ pkg/controller/operators/catalog/operator.go | 66 ++++++++++++++--- pkg/controller/registry/resolver/evolver.go | 35 +++++++++- .../registry/resolver/generation.go | 34 +++++++-- pkg/controller/registry/resolver/resolver.go | 70 ++++++++++++++----- pkg/lib/queueinformer/resourcequeue.go | 24 +++++++ 6 files changed, 211 insertions(+), 35 deletions(-) diff --git a/pkg/api/apis/operators/v1alpha1/installplan_types.go b/pkg/api/apis/operators/v1alpha1/installplan_types.go index c4800aa0bb..5694f05018 100644 --- a/pkg/api/apis/operators/v1alpha1/installplan_types.go +++ b/pkg/api/apis/operators/v1alpha1/installplan_types.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -84,6 +85,7 @@ type InstallPlanStatus struct { Conditions []InstallPlanCondition `json:"conditions,omitempty"` CatalogSources []string `json:"catalogSources"` Plan []*Step `json:"plan,omitempty"` + BundleLookups []*BundleLookup `json:"bundleLookup,omitempty"` // AttenuatedServiceAccountRef references the service account that is used // to do scoped operator install. @@ -162,6 +164,21 @@ type Step struct { Status StepStatus `json:"status"` } +// BundleJob tracks the job status for a given bundle +type BundleJob struct { + Name string `json:"name, omitempty"` + Namespace string `json:"namespace, omitempty"` + Condition batchv1.JobConditionType `json:"condition, omitempty"` + CompletionTime *metav1.Time `json:"completionTime, omitempty"` +} + +// BundleLookup serves as accounting for tracking a bundle data lookup +type BundleLookup struct { + BundleJob *BundleJob `json:"bundleJob"` + ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` + Image *string `json:"image"` +} + // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps // matches those in the InstallPlanStatus. func (s *InstallPlanStatus) CSVManifestsMatch(steps []*Step) bool { diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 67d72ab7d5..9422b911bf 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -11,6 +11,7 @@ import ( errorwrap "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/connectivity" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" @@ -84,6 +85,8 @@ type Operator struct { csvProvidedAPIsIndexer map[string]cache.Indexer clientAttenuator *scoped.ClientAttenuator serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier + + bundleLoader *registry.BundleLoader // 92 } type CatalogSourceSyncFunc func(logger *logrus.Entry, in *v1alpha1.CatalogSource) (out *v1alpha1.CatalogSource, continueSync bool, syncError error) @@ -132,12 +135,13 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo client: crClient, lister: lister, namespace: operatorNamespace, - resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient), + resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient, opClient.KubernetesInterface(), operatorNamespace), catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(), subQueueSet: queueinformer.NewEmptyResourceQueueSet(), csvProvidedAPIsIndexer: map[string]cache.Indexer{}, serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(logger, crClient), clientAttenuator: scoped.NewClientAttenuator(logger, config, opClient, crClient), + bundleLoader: registry.NewBundleLoader(), // 92 } op.sources = grpc.NewSourceStore(logger, 10*time.Second, 10*time.Minute, op.syncSourceState) op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now) @@ -750,7 +754,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error { logger.Debug("resolving subscriptions in namespace") // resolve a set of steps to apply to a cluster, a set of subscriptions to create/update, and any errors - steps, updatedSubs, err := o.resolver.ResolveSteps(namespace, querier) + steps, bundleLookups, updatedSubs, err := o.resolver.ResolveSteps(namespace, querier) if err != nil { return err } @@ -768,7 +772,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error { } } - installPlanReference, err := o.ensureInstallPlan(logger, namespace, subs, installPlanApproval, steps) + installPlanReference, err := o.ensureInstallPlan(logger, namespace, subs, installPlanApproval, steps, bundleLookups) if err != nil { logger.WithError(err).Debug("error ensuring installplan") return err @@ -865,7 +869,7 @@ func (o *Operator) ensureSubscriptionCSVState(logger *logrus.Entry, sub *v1alpha return nil, false, err } bundle, _, _ := querier.FindReplacement(&csv.Spec.Version.Version, sub.Status.CurrentCSV, sub.Spec.Package, sub.Spec.Channel, resolver.CatalogKey{Name: sub.Spec.CatalogSource, Namespace: sub.Spec.CatalogSourceNamespace}) - if bundle != nil { + if bundle != nil || bundle.BundlePath != nil { o.logger.Tracef("replacement %s bundle found for current bundle %s", bundle.CsvName, sub.Status.CurrentCSV) out.Status.State = v1alpha1.SubscriptionStateUpgradeAvailable } else { @@ -909,8 +913,8 @@ func (o *Operator) updateSubscriptionStatus(namespace string, subs []*v1alpha1.S return err } -func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*corev1.ObjectReference, error) { - if len(steps) == 0 { +func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step, bundleLookups []*v1alpha1.BundleLookup) (*corev1.ObjectReference, error) { + if len(steps) == 0 && len(bundleLookups) == 0 { return nil, nil } @@ -956,11 +960,11 @@ func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, sub } logger.Warn("no installplan found with matching manifests, creating new one") - return o.createInstallPlan(namespace, subs, installPlanApproval, steps) + return o.createInstallPlan(namespace, subs, installPlanApproval, steps, bundleLookups) } -func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*corev1.ObjectReference, error) { - if len(steps) == 0 { +func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step, bundleLookups []*v1alpha1.BundleLookup) (*corev1.ObjectReference, error) { + if len(steps) == 0 && len(bundleLookups) == 0 { return nil, nil } @@ -1005,6 +1009,7 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip Phase: phase, Plan: steps, CatalogSources: catalogSources, + BundleLookups: bundleLookups, } res, err = o.client.OperatorsV1alpha1().InstallPlans(namespace).UpdateStatus(res) if err != nil { @@ -1014,6 +1019,35 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip return reference.GetReference(res) } +func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { + allFinished := true + for _, bundleLookup := range plan.Status.BundleLookups { + job, err := o.opClient.KubernetesInterface().BatchV1().Jobs(bundleLookup.BundleJob.Namespace).Get(bundleLookup.BundleJob.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + if len(job.Status.Conditions) > 0 && job.Status.Conditions[0].Type != batchv1.JobComplete { + allFinished = false + continue + } + bundleLookup.BundleJob.Condition = job.Status.Conditions[0].Type + bundleLookup.BundleJob.CompletionTime = job.Status.CompletionTime + + configmap, err := o.opClient.KubernetesInterface().CoreV1().ConfigMaps(bundleLookup.ConfigMapRef.Namespace).Get(bundleLookup.ConfigMapRef.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + // JPEELER HERE + // extract data from configmap and write to install plan + // depends on https://github.com/operator-framework/operator-registry/pull/92/ + manifest, err := o.bundleLoader.Load(configmap) + // will i need to do anything besides call NewStepResourceFromBundle and inject into installplan? + + } + + return allFinished, nil +} + func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) { plan, ok := obj.(*v1alpha1.InstallPlan) if !ok { @@ -1030,11 +1064,23 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) { logger.Info("syncing") - if len(plan.Status.Plan) == 0 { + if len(plan.Status.Plan) == 0 && len(plan.Status.BundleLookups) == 0 { logger.Info("skip processing installplan without status - subscription sync responsible for initial status") return } + // handle bundle data before trying to install + if len(plan.Status.BundleLookups) != 0 { + finished, err := o.checkBundleLookups(plan) + if err != nil { + return fmt.Errorf("BundleLookups failed: %v", err) + } + if !finished { + o.ipQueueSet.RequeueAfter(plan.GetNamespace(), plan.GetName(), 5*time.Second) + return + } + } + querier := o.serviceAccountQuerier.NamespaceQuerier(plan.GetNamespace()) reference, err := querier() if err != nil { diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index 8d630e4ddf..b7fe9c6b3e 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -60,6 +60,12 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { bundle, key, err := e.querier.FindReplacement(op.Version(), op.Identifier(), op.SourceInfo().Package, op.SourceInfo().Channel, op.SourceInfo().Catalog) if err != nil || bundle == nil { + if bundle.BundlePath != nil { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: op.SourceInfo(), + image: bundle.BundlePath, + }) + } continue } @@ -80,11 +86,26 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] for s := range add { var bundle *api.Bundle var key *CatalogKey + var bundlePath *string var err error if s.StartingCSV != "" { bundle, key, err = e.querier.FindBundle(s.Package, s.Channel, s.StartingCSV, s.Catalog) + if bundle.BundlePath != nil { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: &s, + image: bundle.BundlePath, + }) + continue + } } else { bundle, key, err = e.querier.FindLatestBundle(s.Package, s.Channel, s.Catalog) + if bundle.BundlePath != nil { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: &s, + image: bundle.BundlePath, + }) + continue + } } if err != nil { // TODO: log or collect warnings @@ -115,14 +136,22 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error { e.gen.MarkAPIChecked(*api) // identify the initialSource - initialSource := CatalogKey{} + var initialSource *OperatorSourceInfo for _, operator := range e.gen.MissingAPIs()[*api] { - initialSource = operator.SourceInfo().Catalog + initialSource = operator.SourceInfo() break } // attempt to find a bundle that provides that api - if bundle, key, err := e.querier.FindProvider(*api, initialSource); err == nil { + if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog); err == nil { + if bundle.BundlePath != nil { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: initialSource, + image: bundle.BundlePath, + }) + return nil + } + // add a bundle that provides the api to the generation o, err := NewOperatorFromBundle(bundle, "", *key) if err != nil { diff --git a/pkg/controller/registry/resolver/generation.go b/pkg/controller/registry/resolver/generation.go index cc4262490a..946a92f95d 100644 --- a/pkg/controller/registry/resolver/generation.go +++ b/pkg/controller/registry/resolver/generation.go @@ -11,6 +11,8 @@ import ( type Generation interface { AddOperator(o OperatorSurface) error RemoveOperator(o OperatorSurface) + AddPendingOperator(l LaunchBundleImageInfo) + RemovePendingOperator(l LaunchBundleImageInfo) ResetUnchecked() MissingAPIs() APIMultiOwnerSet Operators() OperatorSet @@ -18,13 +20,21 @@ type Generation interface { UncheckedAPIs() APISet } +type LaunchBundleImageInfo struct { + operatorSourceInfo *OperatorSourceInfo + image *string +} + +type BundleImageSet map[LaunchBundleImageInfo]struct{} + // NamespaceGeneration represents a generation of operators in a single namespace with methods for managing api checks type NamespaceGeneration struct { - providedAPIs APIOwnerSet // only allow one provider of any api - requiredAPIs APIMultiOwnerSet // multiple operators may require the same api - uncheckedAPIs APISet // required apis that haven't been checked yet - missingAPIs APIMultiOwnerSet - operators OperatorSet + providedAPIs APIOwnerSet // only allow one provider of any api + requiredAPIs APIMultiOwnerSet // multiple operators may require the same api + uncheckedAPIs APISet // required apis that haven't been checked yet + missingAPIs APIMultiOwnerSet + operators OperatorSet + pendingOperators BundleImageSet } func NewEmptyGeneration() *NamespaceGeneration { @@ -67,6 +77,16 @@ func NewGenerationFromCluster(csvs []*v1alpha1.ClusterServiceVersion, subs []*v1 return g, nil } +func (g *NamespaceGeneration) AddPendingOperator(l LaunchBundleImageInfo) { + g.pendingOperators[l] = struct{}{} +} + +func (g *NamespaceGeneration) RemovePendingOperator(l LaunchBundleImageInfo) { + for pendingOperator := range g.pendingOperators { + delete(g.pendingOperators, pendingOperator) + } +} + func (g *NamespaceGeneration) AddOperator(o OperatorSurface) error { // add provided apis, error if two owners (that isn't a replacement) for api := range o.ProvidedAPIs() { @@ -147,3 +167,7 @@ func (g *NamespaceGeneration) UncheckedAPIs() APISet { func (g *NamespaceGeneration) Operators() OperatorSet { return g.operators } + +func (g *NamespaceGeneration) PendingOperators() BundleImageSet { + return g.pendingOperators +} diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index 9aa93fc91d..fde3123614 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -9,6 +9,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/kubernetes" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" @@ -19,34 +20,38 @@ import ( var timeNow = func() metav1.Time { return metav1.NewTime(time.Now().UTC()) } type Resolver interface { - ResolveSteps(namespace string, sourceQuerier SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) + ResolveSteps(namespace string, sourceQuerier SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) } type OperatorsV1alpha1Resolver struct { - subLister v1alpha1listers.SubscriptionLister - csvLister v1alpha1listers.ClusterServiceVersionLister - client versioned.Interface + subLister v1alpha1listers.SubscriptionLister + csvLister v1alpha1listers.ClusterServiceVersionLister + client versioned.Interface + kubeclient kubernetes.Interface + operatorNamespace string } var _ Resolver = &OperatorsV1alpha1Resolver{} -func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client versioned.Interface) *OperatorsV1alpha1Resolver { +func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client versioned.Interface, kubeclient kubernetes.Interface, operatorNamespace string) *OperatorsV1alpha1Resolver { return &OperatorsV1alpha1Resolver{ - subLister: lister.OperatorsV1alpha1().SubscriptionLister(), - csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(), - client: client, + subLister: lister.OperatorsV1alpha1().SubscriptionLister(), + csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(), + client: client, + kubeclient: kubeclient, + operatorNamespace: operatorNamespace, } } -func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) { +func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) { if err := sourceQuerier.Queryable(); err != nil { - return nil, nil, err + return nil, nil, nil, err } // create a generation - a representation of the current set of installed operators and their provided/required apis allCSVs, err := r.csvLister.ClusterServiceVersions(namespace).List(labels.Everything()) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // TODO: build this index ahead of time @@ -60,12 +65,12 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier subs, err := r.listSubscriptions(namespace) if err != nil { - return nil, nil, err + return nil, nil, nil, err } gen, err := NewGenerationFromCluster(csvs, subs) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // create a map of operatorsourceinfo (subscription+catalogsource data) to the original subscriptions @@ -76,7 +81,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier // evolve a generation by resolving the set of subscriptions (in `add`) by querying with `source` // and taking the current generation (in `gen`) into account if err := NewNamespaceGenerationEvolver(sourceQuerier, gen).Evolve(add); err != nil { - return nil, nil, err + return nil, nil, nil, err } // if there's no error, we were able to satsify all constraints in the subscription set, so we calculate what @@ -96,7 +101,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier if op.Bundle() != nil { bundleSteps, err := NewStepResourceFromBundle(op.Bundle(), namespace, op.Replaces(), op.SourceInfo().Catalog.Name, op.SourceInfo().Catalog.Namespace) if err != nil { - return nil, nil, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) + return nil, nil, nil, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) } for _, s := range bundleSteps { steps = append(steps, &v1alpha1.Step{ @@ -112,7 +117,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier op.SourceInfo().StartingCSV = op.Identifier() subStep, err := NewSubscriptionStepResource(namespace, *op.SourceInfo()) if err != nil { - return nil, nil, err + return nil, nil, nil, err } steps = append(steps, &v1alpha1.Step{ Resolving: name, @@ -129,7 +134,38 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier } } - return steps, updatedSubs, nil + // process other operators first + bundleLookups := []*v1alpha1.BundleLookup{} + for bundleImageInfo := range gen.PendingOperators() { + // TODO: switch image to standalone image, but this image can be used upstream as well + configmap, job, err := LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:lastest", r.operatorNamespace) + if err != nil { + return err + } + gen.RemovePendingOperator(bundleImageInfo) + + bundleLookups = append(bundleLookups, &v1alpha1.BundleLookup{ + BundleJob: &v1alpha1.BundleJob{ + // job condition and completion time will be filled out later (installplan sync) + Name: job.GetName(), + Namespace: job.GetNamespace(), + }, + ConfigMapRef: &v1alpha1.ConfigMapResourceReference{ + Name: configmap.GetName(), + Namespace: configmap.GetNamespace(), + UID: configmap.GetUID(), + ResourceVersion: configmap.GetResourceVersion(), + }, + Image: bundleImageInfo.image, + }) + + existingSubscription, subExists := subMap[*bundleImageInfo.operatorSourceInfo] + if !subExists { + updatedSubs = append(updatedSubs, existingSubscription) + } + } + + return steps, bundleLookups, updatedSubs, nil } func (r *OperatorsV1alpha1Resolver) sourceInfoForNewSubscriptions(namespace string, subs map[OperatorSourceInfo]*v1alpha1.Subscription) (add map[OperatorSourceInfo]struct{}) { diff --git a/pkg/lib/queueinformer/resourcequeue.go b/pkg/lib/queueinformer/resourcequeue.go index bf46733b24..d52c9e66e7 100644 --- a/pkg/lib/queueinformer/resourcequeue.go +++ b/pkg/lib/queueinformer/resourcequeue.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" "sync" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/workqueue" @@ -68,6 +69,29 @@ func (r *ResourceQueueSet) Requeue(namespace, name string) error { return fmt.Errorf("couldn't find queue for resource") } +// TODO: this may not actually be required if the requeue is done on the namespace rather than the installplan +// RequeueAfter requeues the resource in the set with the given name and namespace (just like Requeue), but only does so after duration has passed +func (r *ResourceQueueSet) RequeueAfter(namespace, name string, duration time.Duration) error { + r.mutex.RLock() + defer r.mutex.RUnlock() + + // We can build the key directly, will need to change if queue uses different key scheme + key := fmt.Sprintf("%s/%s", namespace, name) + event := kubestate.NewResourceEvent(kubestate.ResourceUpdated, key) + + if queue, ok := r.queueSet[metav1.NamespaceAll]; len(r.queueSet) == 1 && ok { + queue.AddAfter(event, duration) + return nil + } + + if queue, ok := r.queueSet[namespace]; ok { + queue.AddAfter(event, duration) + return nil + } + + return fmt.Errorf("couldn't find queue for resource") +} + // RequeueByKey adds the given key to the resource queue that should contain it func (r *ResourceQueueSet) RequeueByKey(key string) error { r.mutex.RLock() From f47766e5c66fab70a03a7aa920512cf097d82512 Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Thu, 31 Oct 2019 12:46:06 -0400 Subject: [PATCH 06/12] more wip --- .../operators/v1alpha1/installplan_types.go | 11 +++- pkg/controller/operators/catalog/operator.go | 61 ++++++++++++++++--- pkg/controller/registry/resolver/evolver.go | 13 ++-- .../registry/resolver/generation.go | 4 +- pkg/controller/registry/resolver/resolver.go | 11 +++- 5 files changed, 78 insertions(+), 22 deletions(-) diff --git a/pkg/api/apis/operators/v1alpha1/installplan_types.go b/pkg/api/apis/operators/v1alpha1/installplan_types.go index 5694f05018..31e17a7c75 100644 --- a/pkg/api/apis/operators/v1alpha1/installplan_types.go +++ b/pkg/api/apis/operators/v1alpha1/installplan_types.go @@ -7,6 +7,8 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/operator-framework/operator-registry/pkg/api" ) const ( @@ -174,9 +176,12 @@ type BundleJob struct { // BundleLookup serves as accounting for tracking a bundle data lookup type BundleLookup struct { - BundleJob *BundleJob `json:"bundleJob"` - ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` - Image *string `json:"image"` + BundleJob *BundleJob `json:"bundleJob"` + ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` + Image string `json:"image"` + BundleFromRegistry *api.Bundle `json:"bundleFromRegistry"` + CatalogName string `json:"catalogName"` + CatalogNamespace string `json:"catalogNamespace"` } // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 9422b911bf..d8dd81a7c3 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -32,6 +32,8 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc" sharedtime "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/time" + "github.com/operator-framework/operator-registry/pkg/configmap" + "github.com/operator-framework/operator-registry/pkg/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/reference" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" @@ -86,7 +88,7 @@ type Operator struct { clientAttenuator *scoped.ClientAttenuator serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier - bundleLoader *registry.BundleLoader // 92 + bundleLoader *configmap.BundleLoader } type CatalogSourceSyncFunc func(logger *logrus.Entry, in *v1alpha1.CatalogSource) (out *v1alpha1.CatalogSource, continueSync bool, syncError error) @@ -141,7 +143,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo csvProvidedAPIsIndexer: map[string]cache.Indexer{}, serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(logger, crClient), clientAttenuator: scoped.NewClientAttenuator(logger, config, opClient, crClient), - bundleLoader: registry.NewBundleLoader(), // 92 + bundleLoader: configmap.NewBundleLoader(), } op.sources = grpc.NewSourceStore(logger, 10*time.Second, 10*time.Minute, op.syncSourceState) op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now) @@ -869,7 +871,7 @@ func (o *Operator) ensureSubscriptionCSVState(logger *logrus.Entry, sub *v1alpha return nil, false, err } bundle, _, _ := querier.FindReplacement(&csv.Spec.Version.Version, sub.Status.CurrentCSV, sub.Spec.Package, sub.Spec.Channel, resolver.CatalogKey{Name: sub.Spec.CatalogSource, Namespace: sub.Spec.CatalogSourceNamespace}) - if bundle != nil || bundle.BundlePath != nil { + if bundle != nil || bundle.BundlePath != "" { o.logger.Tracef("replacement %s bundle found for current bundle %s", bundle.CsvName, sub.Status.CurrentCSV) out.Status.State = v1alpha1.SubscriptionStateUpgradeAvailable } else { @@ -1020,15 +1022,17 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip } func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { - allFinished := true + //allFinished := true for _, bundleLookup := range plan.Status.BundleLookups { job, err := o.opClient.KubernetesInterface().BatchV1().Jobs(bundleLookup.BundleJob.Namespace).Get(bundleLookup.BundleJob.Name, metav1.GetOptions{}) if err != nil { return false, err } if len(job.Status.Conditions) > 0 && job.Status.Conditions[0].Type != batchv1.JobComplete { - allFinished = false - continue + // TODO: could write steps for each bundle image as ready + //allFinished = false + //continue + return false, nil } bundleLookup.BundleJob.Condition = job.Status.Conditions[0].Type bundleLookup.BundleJob.CompletionTime = job.Status.CompletionTime @@ -1037,15 +1041,52 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) if err != nil { return false, err } - // JPEELER HERE + // extract data from configmap and write to install plan - // depends on https://github.com/operator-framework/operator-registry/pull/92/ manifest, err := o.bundleLoader.Load(configmap) - // will i need to do anything besides call NewStepResourceFromBundle and inject into installplan? + if err != nil { + return false, err + } + + // combine data from the bundle image into what's already known from the registry + bundleLookup.BundleFromRegistry.CsvName = manifest.Bundle.Name + bundleLookup.BundleFromRegistry.PackageName = manifest.Bundle.Package + bundleLookup.BundleFromRegistry.ChannelName = manifest.Bundle.Channel + _, jsonCSV, _, err := manifest.Bundle.Serialize() + if err != nil { + return false, fmt.Errorf("serialize failed: %s", err.Error()) + } + bundleLookup.BundleFromRegistry.CsvJson = string(jsonCSV) + bundleLookup.BundleFromRegistry.Object, err = registry.BundleStringToObjectStrings(bundleLookup.BundleFromRegistry.CsvJson) + if err != nil { + return false, fmt.Errorf("toStrings failed: %s", err.Error()) + } + var olmCSV *v1alpha1.ClusterServiceVersion + err = json.Unmarshal(jsonCSV, olmCSV) + if err != nil { + return false, fmt.Errorf("csv retrieval failed: %s", err.Error()) + } + + // TODO: refactor with resolver code + bundleSteps, err := resolver.NewStepResourceFromBundle(bundleLookup.BundleFromRegistry, plan.GetNamespace(), olmCSV.Spec.Replaces, bundleLookup.CatalogName, bundleLookup.CatalogNamespace) + if err != nil { + return false, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) + } + + for _, s := range bundleSteps { + plan.Status.Plan = append(plan.Status.Plan, &v1alpha1.Step{ + Resolving: olmCSV.GetName(), + Resource: s, + Status: v1alpha1.StepStatusUnknown, + }) + } } - return allFinished, nil + if _, err := o.client.OperatorsV1alpha1().InstallPlans(plan.GetNamespace()).UpdateStatus(plan); err != nil { + return false, err + } + return true, nil } func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) { diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index b7fe9c6b3e..e1aadc81c7 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -60,10 +60,11 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { bundle, key, err := e.querier.FindReplacement(op.Version(), op.Identifier(), op.SourceInfo().Package, op.SourceInfo().Channel, op.SourceInfo().Catalog) if err != nil || bundle == nil { - if bundle.BundlePath != nil { + if bundle.BundlePath != "" { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: op.SourceInfo(), image: bundle.BundlePath, + bundle: bundle, }) } continue @@ -86,23 +87,24 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] for s := range add { var bundle *api.Bundle var key *CatalogKey - var bundlePath *string var err error if s.StartingCSV != "" { bundle, key, err = e.querier.FindBundle(s.Package, s.Channel, s.StartingCSV, s.Catalog) - if bundle.BundlePath != nil { + if bundle.BundlePath != "" { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: &s, image: bundle.BundlePath, + bundle: bundle, }) continue } } else { bundle, key, err = e.querier.FindLatestBundle(s.Package, s.Channel, s.Catalog) - if bundle.BundlePath != nil { + if bundle.BundlePath != "" { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: &s, image: bundle.BundlePath, + bundle: bundle, }) continue } @@ -144,10 +146,11 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error { // attempt to find a bundle that provides that api if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog); err == nil { - if bundle.BundlePath != nil { + if bundle.BundlePath != "" { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: initialSource, image: bundle.BundlePath, + bundle: bundle, }) return nil } diff --git a/pkg/controller/registry/resolver/generation.go b/pkg/controller/registry/resolver/generation.go index 946a92f95d..62322ff221 100644 --- a/pkg/controller/registry/resolver/generation.go +++ b/pkg/controller/registry/resolver/generation.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" + "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/registry" ) @@ -22,7 +23,8 @@ type Generation interface { type LaunchBundleImageInfo struct { operatorSourceInfo *OperatorSourceInfo - image *string + image string + bundle *api.Bundle } type BundleImageSet map[LaunchBundleImageInfo]struct{} diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index fde3123614..aefc0649d5 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -11,6 +11,8 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" + "github.com/operator-framework/operator-registry/pkg/configmap" + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1" @@ -138,9 +140,9 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier bundleLookups := []*v1alpha1.BundleLookup{} for bundleImageInfo := range gen.PendingOperators() { // TODO: switch image to standalone image, but this image can be used upstream as well - configmap, job, err := LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:lastest", r.operatorNamespace) + configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:lastest", r.operatorNamespace) if err != nil { - return err + return nil, nil, nil, err } gen.RemovePendingOperator(bundleImageInfo) @@ -156,7 +158,10 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier UID: configmap.GetUID(), ResourceVersion: configmap.GetResourceVersion(), }, - Image: bundleImageInfo.image, + Image: bundleImageInfo.image, + BundleFromRegistry: bundleImageInfo.bundle, + CatalogName: bundleImageInfo.operatorSourceInfo.Catalog.Name, + CatalogNamespace: bundleImageInfo.operatorSourceInfo.Catalog.Namespace, }) existingSubscription, subExists := subMap[*bundleImageInfo.operatorSourceInfo] From 75e6c7873caa3091da8f7f97cd851b95595f87bc Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Wed, 30 Oct 2019 17:08:54 -0400 Subject: [PATCH 07/12] WIP --- test/e2e/installplan_e2e_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/e2e/installplan_e2e_test.go b/test/e2e/installplan_e2e_test.go index 970d4ec4d6..e496b497bf 100644 --- a/test/e2e/installplan_e2e_test.go +++ b/test/e2e/installplan_e2e_test.go @@ -2526,3 +2526,13 @@ func TestInstallPlanCRDValidation(t *testing.T) { require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) } + +func TestInstallPlanFromBundleImage(t *testing.T) { + // Create the CatalogSource + c := newKubeClient(t) + crc := newCRClient(t) + catalogSourceName := genName("mock-nginx-") + _, cleanupCatalogSource := createInternalCatalogSource(t, c, crc, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv}) + defer cleanupCatalogSource() + +} From f07a66277e5548ec023d6bcef836a4c6d0c239da Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Fri, 1 Nov 2019 12:34:43 -0400 Subject: [PATCH 08/12] wip that's all i do! --- pkg/controller/operators/catalog/operator.go | 14 +- pkg/controller/registry/resolver/evolver.go | 2 +- .../registry/resolver/generation.go | 15 +- pkg/controller/registry/resolver/resolver.go | 48 ++++- test/e2e/installplan_e2e_test.go | 183 +++++++++++++++++- 5 files changed, 237 insertions(+), 25 deletions(-) diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index d8dd81a7c3..58be987085 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -140,6 +140,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient, opClient.KubernetesInterface(), operatorNamespace), catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(), subQueueSet: queueinformer.NewEmptyResourceQueueSet(), + ipQueueSet: queueinformer.NewEmptyResourceQueueSet(), csvProvidedAPIsIndexer: map[string]cache.Indexer{}, serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(logger, crClient), clientAttenuator: scoped.NewClientAttenuator(logger, config, opClient, crClient), @@ -762,7 +763,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error { } // create installplan if anything updated - if len(updatedSubs) > 0 { + if len(updatedSubs) > 0 || len(bundleLookups) > 0 { logger.Debug("resolution caused subscription changes, creating installplan") // any subscription in the namespace with manual approval will force generated installplans to be manual // TODO: this is an odd artifact of the older resolver, and will probably confuse users. approval mode could be on the operatorgroup? @@ -1022,16 +1023,13 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip } func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { - //allFinished := true for _, bundleLookup := range plan.Status.BundleLookups { job, err := o.opClient.KubernetesInterface().BatchV1().Jobs(bundleLookup.BundleJob.Namespace).Get(bundleLookup.BundleJob.Name, metav1.GetOptions{}) if err != nil { return false, err } - if len(job.Status.Conditions) > 0 && job.Status.Conditions[0].Type != batchv1.JobComplete { - // TODO: could write steps for each bundle image as ready - //allFinished = false - //continue + if len(job.Status.Conditions) == 0 || len(job.Status.Conditions) > 0 && job.Status.Conditions[0].Type != batchv1.JobComplete { + logrus.Infof("Job '%v' not yet completed", job.GetName()) return false, nil } bundleLookup.BundleJob.Condition = job.Status.Conditions[0].Type @@ -1062,8 +1060,8 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) return false, fmt.Errorf("toStrings failed: %s", err.Error()) } - var olmCSV *v1alpha1.ClusterServiceVersion - err = json.Unmarshal(jsonCSV, olmCSV) + var olmCSV v1alpha1.ClusterServiceVersion + err = json.Unmarshal(jsonCSV, &olmCSV) if err != nil { return false, fmt.Errorf("csv retrieval failed: %s", err.Error()) } diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index e1aadc81c7..e07bf5a9d9 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -100,7 +100,7 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] } } else { bundle, key, err = e.querier.FindLatestBundle(s.Package, s.Channel, s.Catalog) - if bundle.BundlePath != "" { + if bundle != nil && bundle.BundlePath != "" { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: &s, image: bundle.BundlePath, diff --git a/pkg/controller/registry/resolver/generation.go b/pkg/controller/registry/resolver/generation.go index 62322ff221..610f78020a 100644 --- a/pkg/controller/registry/resolver/generation.go +++ b/pkg/controller/registry/resolver/generation.go @@ -29,6 +29,10 @@ type LaunchBundleImageInfo struct { type BundleImageSet map[LaunchBundleImageInfo]struct{} +func EmptyImageSet() BundleImageSet { + return map[LaunchBundleImageInfo]struct{}{} +} + // NamespaceGeneration represents a generation of operators in a single namespace with methods for managing api checks type NamespaceGeneration struct { providedAPIs APIOwnerSet // only allow one provider of any api @@ -41,11 +45,12 @@ type NamespaceGeneration struct { func NewEmptyGeneration() *NamespaceGeneration { return &NamespaceGeneration{ - providedAPIs: EmptyAPIOwnerSet(), - requiredAPIs: EmptyAPIMultiOwnerSet(), - uncheckedAPIs: EmptyAPISet(), - missingAPIs: EmptyAPIMultiOwnerSet(), - operators: EmptyOperatorSet(), + providedAPIs: EmptyAPIOwnerSet(), + requiredAPIs: EmptyAPIMultiOwnerSet(), + uncheckedAPIs: EmptyAPISet(), + missingAPIs: EmptyAPIMultiOwnerSet(), + operators: EmptyOperatorSet(), + pendingOperators: EmptyImageSet(), } } diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index aefc0649d5..f4b143862d 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -6,6 +6,8 @@ import ( "fmt" "time" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -28,6 +30,7 @@ type Resolver interface { type OperatorsV1alpha1Resolver struct { subLister v1alpha1listers.SubscriptionLister csvLister v1alpha1listers.ClusterServiceVersionLister + ipLister v1alpha1listers.InstallPlanLister client versioned.Interface kubeclient kubernetes.Interface operatorNamespace string @@ -39,6 +42,7 @@ func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client v return &OperatorsV1alpha1Resolver{ subLister: lister.OperatorsV1alpha1().SubscriptionLister(), csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(), + ipLister: lister.OperatorsV1alpha1().InstallPlanLister(), client: client, kubeclient: kubeclient, operatorNamespace: operatorNamespace, @@ -138,13 +142,34 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier // process other operators first bundleLookups := []*v1alpha1.BundleLookup{} + + // prune operators that have in progress bundle image jobs + for bundleImageInfo := range gen.PendingOperators() { + // TODO: this is not ideal... + ips, err := r.listInstallPlans(namespace) + if err != nil { + return nil, nil, nil, err + } + for _, ip := range ips { + for _, lookup := range ip.Status.BundleLookups { + if lookup.Image == bundleImageInfo.image { + logrus.Debugf("found existing install plan, skipping bundle image %v", lookup.Image) + gen.RemovePendingOperator(bundleImageInfo) + } + } + } + } + for bundleImageInfo := range gen.PendingOperators() { // TODO: switch image to standalone image, but this image can be used upstream as well - configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:lastest", r.operatorNamespace) + // change to use configmapRegistryImage + //configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:latest", r.operatorNamespace) + + configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/jpeeler/bundle-init-image:latest", r.operatorNamespace) if err != nil { return nil, nil, nil, err } - gen.RemovePendingOperator(bundleImageInfo) + logrus.Infof("Launched bundle job for image %v", bundleImageInfo.image) bundleLookups = append(bundleLookups, &v1alpha1.BundleLookup{ BundleJob: &v1alpha1.BundleJob{ @@ -163,11 +188,6 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier CatalogName: bundleImageInfo.operatorSourceInfo.Catalog.Name, CatalogNamespace: bundleImageInfo.operatorSourceInfo.Catalog.Namespace, }) - - existingSubscription, subExists := subMap[*bundleImageInfo.operatorSourceInfo] - if !subExists { - updatedSubs = append(updatedSubs, existingSubscription) - } } return steps, bundleLookups, updatedSubs, nil @@ -226,3 +246,17 @@ func (r *OperatorsV1alpha1Resolver) listSubscriptions(namespace string) (subs [] return } + +func (r *OperatorsV1alpha1Resolver) listInstallPlans(namespace string) (ips []*v1alpha1.InstallPlan, err error) { + list, err := r.client.OperatorsV1alpha1().InstallPlans(namespace).List(metav1.ListOptions{}) + if err != nil { + return + } + + ips = make([]*v1alpha1.InstallPlan, 0) + for i := range list.Items { + ips = append(ips, &list.Items[i]) + } + + return +} diff --git a/test/e2e/installplan_e2e_test.go b/test/e2e/installplan_e2e_test.go index e496b497bf..c241c514f3 100644 --- a/test/e2e/installplan_e2e_test.go +++ b/test/e2e/installplan_e2e_test.go @@ -17,10 +17,14 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" "k8s.io/kubernetes/pkg/apis/rbac" + //"github.com/operator-framework/operator-registry/pkg/configmap" + //"github.com/operator-framework/operator-registry/pkg/lib/bundle" + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" @@ -2528,11 +2532,182 @@ func TestInstallPlanCRDValidation(t *testing.T) { } func TestInstallPlanFromBundleImage(t *testing.T) { - // Create the CatalogSource c := newKubeClient(t) crc := newCRClient(t) - catalogSourceName := genName("mock-nginx-") - _, cleanupCatalogSource := createInternalCatalogSource(t, c, crc, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv}) - defer cleanupCatalogSource() + catalogSourceName := genName("mock-kiali-") + + // add RBAC for e2e namespace + rbacRole := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm-e2e-configmap-access", + Namespace: testNamespace, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{ + "", + }, + Verbs: []string{ + "create", "get", "update", + }, + Resources: []string{ + "configmaps", + }, + }, + }, + } + _, err := c.KubernetesInterface().RbacV1().Roles(testNamespace).Create(rbacRole) + require.NoError(t, err) + + rbacBinding := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "olm-e2e-configmap-access-binding", + Namespace: testNamespace, + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: "", + Name: "default", + Namespace: testNamespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: rbacRole.GetName(), + }, + } + _, err = c.KubernetesInterface().RbacV1().RoleBindings(testNamespace).Create(rbacBinding) + require.NoError(t, err) + + // crd := apiextensions.CustomResourceDefinition{ + // ObjectMeta: metav1.ObjectMeta{ + // Name: "kialis.kialio.io", + // }, + // Spec: apiextensions.CustomResourceDefinitionSpec{ + // Group: "kiali.io", + // Version: "v1alpha1", + // Names: apiextensions.CustomResourceDefinitionNames{ + // Plural: "kialis", + // Singular: "kiali", + // Kind: "Kiali", + // ListKind: "KialiList", + // }, + // Scope: "Namespaced", + // }, + // } + + //packageName := "kiali-operator.v1.4.2" + // annotations := map[string]string{ + // bundle.MediatypeLabel: "registry+v1", + // bundle.ManifestsLabel: "/manifests/", + // bundle.MetadataLabel: "/metadata/", + // bundle.PackageLabel: packageName, + // bundle.ChannelsLabel: "alpha,stable", + // bundle.ChannelDefaultLabel: stableChannel, + // configmap.ConfigMapImageAnnotationKey: "bundle-image-ubi:latest", + // } + + // manifests and csvs are intentionally set to nil + //_, cleanupCatalogSource := createInternalCatalogSourceWithAnnotations(t, c, crc, catalogSourceName, testNamespace, nil, []apiextensions.CustomResourceDefinition{crd}, nil, annotations) + //defer cleanupCatalogSource() + + grpcCatalogSource := &v1alpha1.CatalogSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: catalogSourceName, + Namespace: testNamespace, + UID: types.UID("catalog-uid"), + Labels: map[string]string{"olm.catalogSource": "kaili-catalog"}, + }, + Spec: v1alpha1.CatalogSourceSpec{ + Image: "quay.io/jpeeler/registry-image:latest", + SourceType: v1alpha1.SourceTypeGrpc, + }, + } + _, err = crc.OperatorsV1alpha1().CatalogSources(testNamespace).Create(grpcCatalogSource) + require.NoError(t, err) + + // wait for catalog source to be ready + _, err = fetchCatalogSource(t, crc, catalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + require.NoError(t, err) + + // generate subscription + subscriptionName := genName("sub-kiali-") + cleanupSubscription := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, catalogSourceName, "kiali", stableChannel, "", v1alpha1.ApprovalAutomatic) + defer cleanupSubscription() + + subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + installPlanName := subscription.Status.Install.Name + + // get InstallPlan + fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed, v1alpha1.InstallPlanPhaseComplete)) + require.NoError(t, err) + require.NotEqual(t, v1alpha1.InstallPlanPhaseFailed, fetchedInstallPlan.Status.Phase, "InstallPlan failed") + + // verify steps + t.Logf("installPlan=%#v", fetchedInstallPlan) + + // Expect correct RBAC resources to be resolved and created + expectedSteps := map[registry.ResourceKey]struct{}{ + //registry.ResourceKey{Name: crd.Name, Kind: "CustomResourceDefinition"}: {}, + registry.ResourceKey{Name: "kiali-operator.v.1.4.2", Kind: "ClusterServiceVersion"}: {}, + registry.ResourceKey{Name: "kiali-operator", Kind: "ServiceAccount"}: {}, + registry.ResourceKey{Name: "kiali-operator", Kind: "Role"}: {}, + registry.ResourceKey{Name: "kiali-operator", Kind: "RoleBinding"}: {}, + registry.ResourceKey{Name: "kiali-operator", Kind: "ClusterRole"}: {}, + registry.ResourceKey{Name: "kiali-operator", Kind: "ClusterRoleBinding"}: {}, + } + + require.Equal(t, len(expectedSteps), len(fetchedInstallPlan.Status.Plan), "number of expected steps does not match installed") + + for _, step := range fetchedInstallPlan.Status.Plan { + key := registry.ResourceKey{ + Name: step.Resource.Name, + Kind: step.Resource.Kind, + } + for expected := range expectedSteps { + if expected == key { + delete(expectedSteps, expected) + } else if strings.HasPrefix(key.Name, expected.Name) && key.Kind == expected.Kind { + delete(expectedSteps, expected) + } else { + t.Logf("%v, %v: %v && %v", key, expected, strings.HasPrefix(key.Name, expected.Name), key.Kind == expected.Kind) + } + } + + // This operator was installed into a global operator group, so the roles should have been lifted to clusterroles + if step.Resource.Kind == "Role" { + err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { + _, err = c.GetClusterRole(step.Resource.Name) + if err != nil { + if k8serrors.IsNotFound(err) { + return false, nil + } + return false, err + } + return true, nil + }) + } + if step.Resource.Kind == "RoleBinding" { + err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { + _, err = c.GetClusterRoleBinding(step.Resource.Name) + if err != nil { + if k8serrors.IsNotFound(err) { + return false, nil + } + return false, err + } + return true, nil + }) + } + } + + // Should have removed every matching step + require.Equal(t, 0, len(expectedSteps), "Actual resource steps do not match expected: %#v", expectedSteps) + + // check CSV installed successfully } From 614ce4f0baae5ad6b3c047986fa5814ab8ba9a3a Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Sat, 2 Nov 2019 12:04:40 -0400 Subject: [PATCH 09/12] pull in changes from registry pinned for now. --- go.mod | 4 ++++ go.sum | 6 ++++++ .../pkg/configmap/configmap_writer.go | 14 ++++++-------- vendor/modules.txt | 4 ++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index ff74410be5..10bb4ef47f 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,11 @@ require ( github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b +<<<<<<< ours github.com/operator-framework/operator-registry v1.5.3 +======= + github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c +>>>>>>> theirs github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 github.com/sirupsen/logrus v1.4.2 diff --git a/go.sum b/go.sum index 58a8fc0eae..e44ea659d6 100644 --- a/go.sum +++ b/go.sum @@ -288,6 +288,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.4 h1:5xLhQjsk4zqPf9EHCrja2qFZMx+yBqkO3XgJ14bNnU0= github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db h1:UxmGBzaBcWDQuQh9E1iT1dWKQFbizZ+SpTd1EL4MSqs= github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -428,8 +429,13 @@ github.com/operator-framework/operator-registry v1.4.0 h1:yhI7ZeF6d7G588i2egoFjg github.com/operator-framework/operator-registry v1.4.0/go.mod h1:3nJcOSX6TKPpAbmGOAVvDxakZWgccyF0WgiJsKjPAzQ= github.com/operator-framework/operator-registry v1.5.1 h1:8ruUOG6IBDVTAXYWKsv6hwr4yv/0SFPFPAYGCpcv97E= github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= +<<<<<<< ours github.com/operator-framework/operator-registry v1.5.3 h1:az83WDwgB+tHsmVn+tFq72yQBbaUAye8e4+KkDQmzLs= github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= +======= +github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c h1:ozT20B/o6SfMeZr2kjGVvSviTYh0xJ4fHxRPjAfvk7E= +github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= +>>>>>>> theirs github.com/otiai10/copy v1.0.1 h1:gtBjD8aq4nychvRZ2CyJvFWAw0aja+VHazDdruZKGZA= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go index 9a3a2f511b..fbcdcaf66b 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go @@ -164,10 +164,9 @@ func LaunchBundleImage(kubeclient kubernetes.Interface, bundleImage, initImage, RestartPolicy: corev1.RestartPolicyOnFailure, Containers: []corev1.Container{ { - Name: "bundle-image", - Image: bundleImage, - ImagePullPolicy: "Never", - Command: []string{"/injected/opm", "alpha", "bundle", "extract", "-n", namespace, "-c", newConfigMap.GetName()}, + Name: "bundle-image", + Image: bundleImage, + Command: []string{"/injected/opm", "alpha", "bundle", "extract", "-n", namespace, "-c", newConfigMap.GetName()}, Env: []corev1.EnvVar{ { Name: EnvContainerImage, @@ -184,10 +183,9 @@ func LaunchBundleImage(kubeclient kubernetes.Interface, bundleImage, initImage, }, InitContainers: []corev1.Container{ { - Name: "copy-binary", - Image: initImage, - ImagePullPolicy: "Never", - Command: []string{"/bin/cp", "opm", "/copy-dest"}, + Name: "copy-binary", + Image: initImage, + Command: []string{"/bin/cp", "/bin/opm", "/copy-dest"}, VolumeMounts: []corev1.VolumeMount{ { Name: "copydir", diff --git a/vendor/modules.txt b/vendor/modules.txt index ac680abe99..ac4c013022 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -156,7 +156,11 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 +<<<<<<< ours # github.com/operator-framework/operator-registry v1.5.3 +======= +# github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c +>>>>>>> theirs github.com/operator-framework/operator-registry/pkg/api github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1 github.com/operator-framework/operator-registry/pkg/client From cc68e6c98e4e811b24aa89d8d7aad262ba60b531 Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Fri, 1 Nov 2019 17:13:56 -0400 Subject: [PATCH 10/12] working --- .../operators/v1alpha1/installplan_types.go | 13 ++- pkg/controller/operators/catalog/operator.go | 20 +++- pkg/controller/registry/resolver/resolver.go | 2 +- test/e2e/installplan_e2e_test.go | 105 +++++------------- 4 files changed, 50 insertions(+), 90 deletions(-) diff --git a/pkg/api/apis/operators/v1alpha1/installplan_types.go b/pkg/api/apis/operators/v1alpha1/installplan_types.go index 31e17a7c75..e897375d7d 100644 --- a/pkg/api/apis/operators/v1alpha1/installplan_types.go +++ b/pkg/api/apis/operators/v1alpha1/installplan_types.go @@ -176,12 +176,13 @@ type BundleJob struct { // BundleLookup serves as accounting for tracking a bundle data lookup type BundleLookup struct { - BundleJob *BundleJob `json:"bundleJob"` - ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` - Image string `json:"image"` - BundleFromRegistry *api.Bundle `json:"bundleFromRegistry"` - CatalogName string `json:"catalogName"` - CatalogNamespace string `json:"catalogNamespace"` + BundleJob *BundleJob `json:"bundleJob"` + ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` + Image string `json:"image"` + BundleFromRegistry *api.Bundle `json:"bundleFromRegistry"` + CatalogName string `json:"catalogName"` + CatalogNamespace string `json:"catalogNamespace"` + IsInstallPlanUpdated bool `json:"isInstallPlanUpdated"` } // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 58be987085..6496d1313d 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -33,7 +33,6 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc" sharedtime "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/time" "github.com/operator-framework/operator-registry/pkg/configmap" - "github.com/operator-framework/operator-registry/pkg/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/reference" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" @@ -1024,12 +1023,16 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { for _, bundleLookup := range plan.Status.BundleLookups { + if bundleLookup.IsInstallPlanUpdated == true { + continue + } + job, err := o.opClient.KubernetesInterface().BatchV1().Jobs(bundleLookup.BundleJob.Namespace).Get(bundleLookup.BundleJob.Name, metav1.GetOptions{}) if err != nil { return false, err } if len(job.Status.Conditions) == 0 || len(job.Status.Conditions) > 0 && job.Status.Conditions[0].Type != batchv1.JobComplete { - logrus.Infof("Job '%v' not yet completed", job.GetName()) + logrus.Infof("Job '%v' for '%v' not yet completed", job.GetName(), bundleLookup.Image) return false, nil } bundleLookup.BundleJob.Condition = job.Status.Conditions[0].Type @@ -1055,9 +1058,13 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) return false, fmt.Errorf("serialize failed: %s", err.Error()) } bundleLookup.BundleFromRegistry.CsvJson = string(jsonCSV) - bundleLookup.BundleFromRegistry.Object, err = registry.BundleStringToObjectStrings(bundleLookup.BundleFromRegistry.CsvJson) - if err != nil { - return false, fmt.Errorf("toStrings failed: %s", err.Error()) + bundleLookup.BundleFromRegistry.Object = []string{string(jsonCSV)} + for _, item := range manifest.Bundle.Objects { + bytes, err := item.MarshalJSON() + if err != nil { + return false, fmt.Errorf("marshall failed: %v", err) + } + bundleLookup.BundleFromRegistry.Object = append(bundleLookup.BundleFromRegistry.Object, string(bytes)) } var olmCSV v1alpha1.ClusterServiceVersion @@ -1066,7 +1073,7 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) return false, fmt.Errorf("csv retrieval failed: %s", err.Error()) } - // TODO: refactor with resolver code + // TODO: refactor with resolver code (and call the subscription stuff too) bundleSteps, err := resolver.NewStepResourceFromBundle(bundleLookup.BundleFromRegistry, plan.GetNamespace(), olmCSV.Spec.Replaces, bundleLookup.CatalogName, bundleLookup.CatalogNamespace) if err != nil { return false, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) @@ -1079,6 +1086,7 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) Status: v1alpha1.StepStatusUnknown, }) } + bundleLookup.IsInstallPlanUpdated = true } if _, err := o.client.OperatorsV1alpha1().InstallPlans(plan.GetNamespace()).UpdateStatus(plan); err != nil { diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index f4b143862d..87dc789b21 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -140,7 +140,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier } } - // process other operators first + // allow other operators to be processed first, then process ones that require copying data out of image bundleLookups := []*v1alpha1.BundleLookup{} // prune operators that have in progress bundle image jobs diff --git a/test/e2e/installplan_e2e_test.go b/test/e2e/installplan_e2e_test.go index c241c514f3..39a2d4aaf1 100644 --- a/test/e2e/installplan_e2e_test.go +++ b/test/e2e/installplan_e2e_test.go @@ -2581,38 +2581,6 @@ func TestInstallPlanFromBundleImage(t *testing.T) { _, err = c.KubernetesInterface().RbacV1().RoleBindings(testNamespace).Create(rbacBinding) require.NoError(t, err) - // crd := apiextensions.CustomResourceDefinition{ - // ObjectMeta: metav1.ObjectMeta{ - // Name: "kialis.kialio.io", - // }, - // Spec: apiextensions.CustomResourceDefinitionSpec{ - // Group: "kiali.io", - // Version: "v1alpha1", - // Names: apiextensions.CustomResourceDefinitionNames{ - // Plural: "kialis", - // Singular: "kiali", - // Kind: "Kiali", - // ListKind: "KialiList", - // }, - // Scope: "Namespaced", - // }, - // } - - //packageName := "kiali-operator.v1.4.2" - // annotations := map[string]string{ - // bundle.MediatypeLabel: "registry+v1", - // bundle.ManifestsLabel: "/manifests/", - // bundle.MetadataLabel: "/metadata/", - // bundle.PackageLabel: packageName, - // bundle.ChannelsLabel: "alpha,stable", - // bundle.ChannelDefaultLabel: stableChannel, - // configmap.ConfigMapImageAnnotationKey: "bundle-image-ubi:latest", - // } - - // manifests and csvs are intentionally set to nil - //_, cleanupCatalogSource := createInternalCatalogSourceWithAnnotations(t, c, crc, catalogSourceName, testNamespace, nil, []apiextensions.CustomResourceDefinition{crd}, nil, annotations) - //defer cleanupCatalogSource() - grpcCatalogSource := &v1alpha1.CatalogSource{ ObjectMeta: metav1.ObjectMeta{ Name: catalogSourceName, @@ -2637,10 +2605,25 @@ func TestInstallPlanFromBundleImage(t *testing.T) { cleanupSubscription := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, catalogSourceName, "kiali", stableChannel, "", v1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionStateAny) + //subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(t, err) require.NotNil(t, subscription) - installPlanName := subscription.Status.Install.Name + //installPlanName := subscription.Status.Install.Name + + // until subscription references are fixed... +TRYAGAIN: + var installPlanName string + ips, err := crc.OperatorsV1alpha1().InstallPlans(testNamespace).List(metav1.ListOptions{}) + require.NoError(t, err) + for _, ip := range ips.Items { + if ip.GetOwnerReferences()[0].Name == subscriptionName { + installPlanName = ip.GetName() + } + } + if installPlanName == "" { + goto TRYAGAIN + } // get InstallPlan fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed, v1alpha1.InstallPlanPhaseComplete)) @@ -2648,19 +2631,15 @@ func TestInstallPlanFromBundleImage(t *testing.T) { require.NotEqual(t, v1alpha1.InstallPlanPhaseFailed, fetchedInstallPlan.Status.Phase, "InstallPlan failed") // verify steps - t.Logf("installPlan=%#v", fetchedInstallPlan) - - // Expect correct RBAC resources to be resolved and created + operatorName := "kiali-operator" expectedSteps := map[registry.ResourceKey]struct{}{ - //registry.ResourceKey{Name: crd.Name, Kind: "CustomResourceDefinition"}: {}, - registry.ResourceKey{Name: "kiali-operator.v.1.4.2", Kind: "ClusterServiceVersion"}: {}, - registry.ResourceKey{Name: "kiali-operator", Kind: "ServiceAccount"}: {}, - registry.ResourceKey{Name: "kiali-operator", Kind: "Role"}: {}, - registry.ResourceKey{Name: "kiali-operator", Kind: "RoleBinding"}: {}, - registry.ResourceKey{Name: "kiali-operator", Kind: "ClusterRole"}: {}, - registry.ResourceKey{Name: "kiali-operator", Kind: "ClusterRoleBinding"}: {}, + registry.ResourceKey{Name: operatorName, Kind: "ClusterServiceVersion"}: {}, + registry.ResourceKey{Name: "kialis.kiali.io", Kind: "CustomResourceDefinition"}: {}, + registry.ResourceKey{Name: "monitoringdashboards.monitoring.kiali.io", Kind: "CustomResourceDefinition"}: {}, + registry.ResourceKey{Name: operatorName, Kind: "ServiceAccount"}: {}, + registry.ResourceKey{Name: operatorName, Kind: "ClusterRole"}: {}, + registry.ResourceKey{Name: operatorName, Kind: "ClusterRoleBinding"}: {}, } - require.Equal(t, len(expectedSteps), len(fetchedInstallPlan.Status.Plan), "number of expected steps does not match installed") for _, step := range fetchedInstallPlan.Status.Plan { @@ -2669,45 +2648,17 @@ func TestInstallPlanFromBundleImage(t *testing.T) { Kind: step.Resource.Kind, } for expected := range expectedSteps { - if expected == key { - delete(expectedSteps, expected) - } else if strings.HasPrefix(key.Name, expected.Name) && key.Kind == expected.Kind { + if strings.HasPrefix(key.Name, expected.Name) && key.Kind == expected.Kind { delete(expectedSteps, expected) + break } else { t.Logf("%v, %v: %v && %v", key, expected, strings.HasPrefix(key.Name, expected.Name), key.Kind == expected.Kind) } } - - // This operator was installed into a global operator group, so the roles should have been lifted to clusterroles - if step.Resource.Kind == "Role" { - err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - _, err = c.GetClusterRole(step.Resource.Name) - if err != nil { - if k8serrors.IsNotFound(err) { - return false, nil - } - return false, err - } - return true, nil - }) - } - if step.Resource.Kind == "RoleBinding" { - err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - _, err = c.GetClusterRoleBinding(step.Resource.Name) - if err != nil { - if k8serrors.IsNotFound(err) { - return false, nil - } - return false, err - } - return true, nil - }) - } } - - // Should have removed every matching step require.Equal(t, 0, len(expectedSteps), "Actual resource steps do not match expected: %#v", expectedSteps) // check CSV installed successfully - + _, err = fetchCSV(t, crc, "kiali-operator.v1.4.2", testNamespace, csvSucceededChecker) + require.NoError(t, err) } From 586fbbfaa410e57babb16eeb4bc5a81b97a24f09 Mon Sep 17 00:00:00 2001 From: Jeff Peeler Date: Sat, 2 Nov 2019 02:01:22 -0400 Subject: [PATCH 11/12] this fixes subscription references to the install plan and launches bundle images later --- .../operators/v1alpha1/installplan_types.go | 1 - pkg/controller/operators/catalog/operator.go | 38 ++++++++++++++++--- pkg/controller/registry/resolver/evolver.go | 37 +++++++----------- pkg/controller/registry/resolver/resolver.go | 38 ------------------- test/e2e/installplan_e2e_test.go | 23 ++--------- 5 files changed, 51 insertions(+), 86 deletions(-) diff --git a/pkg/api/apis/operators/v1alpha1/installplan_types.go b/pkg/api/apis/operators/v1alpha1/installplan_types.go index e897375d7d..0a52f45c66 100644 --- a/pkg/api/apis/operators/v1alpha1/installplan_types.go +++ b/pkg/api/apis/operators/v1alpha1/installplan_types.go @@ -182,7 +182,6 @@ type BundleLookup struct { BundleFromRegistry *api.Bundle `json:"bundleFromRegistry"` CatalogName string `json:"catalogName"` CatalogNamespace string `json:"catalogNamespace"` - IsInstallPlanUpdated bool `json:"isInstallPlanUpdated"` } // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 6496d1313d..62dc7353ea 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -762,7 +762,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error { } // create installplan if anything updated - if len(updatedSubs) > 0 || len(bundleLookups) > 0 { + if len(updatedSubs) > 0 { logger.Debug("resolution caused subscription changes, creating installplan") // any subscription in the namespace with manual approval will force generated installplans to be manual // TODO: this is an odd artifact of the older resolver, and will probably confuse users. approval mode could be on the operatorgroup? @@ -871,7 +871,7 @@ func (o *Operator) ensureSubscriptionCSVState(logger *logrus.Entry, sub *v1alpha return nil, false, err } bundle, _, _ := querier.FindReplacement(&csv.Spec.Version.Version, sub.Status.CurrentCSV, sub.Spec.Package, sub.Spec.Channel, resolver.CatalogKey{Name: sub.Spec.CatalogSource, Namespace: sub.Spec.CatalogSourceNamespace}) - if bundle != nil || bundle.BundlePath != "" { + if bundle != nil { o.logger.Tracef("replacement %s bundle found for current bundle %s", bundle.CsvName, sub.Status.CurrentCSV) out.Status.State = v1alpha1.SubscriptionStateUpgradeAvailable } else { @@ -1023,10 +1023,38 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { for _, bundleLookup := range plan.Status.BundleLookups { - if bundleLookup.IsInstallPlanUpdated == true { - continue + if bundleLookup.BundleJob == nil { + configmap, job, err := configmap.LaunchBundleImage(o.opClient.KubernetesInterface(), bundleLookup.Image, "quay.io/jpeeler/bundle-init-image:latest", o.namespace) + if err != nil { + return false, err + } + logrus.Infof("Launched bundle job for image %v", bundleLookup.Image) + + bundleLookup.BundleJob = &v1alpha1.BundleJob{ + // job condition and completion time will be filled out later (installplan sync) + Name: job.GetName(), + Namespace: job.GetNamespace(), + } + bundleLookup.ConfigMapRef = &v1alpha1.ConfigMapResourceReference{ + Name: configmap.GetName(), + Namespace: configmap.GetNamespace(), + UID: configmap.GetUID(), + ResourceVersion: configmap.GetResourceVersion(), + } + _, err = o.client.OperatorsV1alpha1().InstallPlans(plan.GetNamespace()).UpdateStatus(plan) + if err != nil { + return false, err + } + + return false, nil + } + + if bundleLookup.BundleJob.CompletionTime != nil { + // already processed + return true, nil } + // TODO: instead of doing a get, should just watch all jobs (add ownerref) and update the installplan from there job, err := o.opClient.KubernetesInterface().BatchV1().Jobs(bundleLookup.BundleJob.Namespace).Get(bundleLookup.BundleJob.Name, metav1.GetOptions{}) if err != nil { return false, err @@ -1079,6 +1107,7 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) return false, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) } + // TODO: could this add duplicate steps? for _, s := range bundleSteps { plan.Status.Plan = append(plan.Status.Plan, &v1alpha1.Step{ Resolving: olmCSV.GetName(), @@ -1086,7 +1115,6 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) Status: v1alpha1.StepStatusUnknown, }) } - bundleLookup.IsInstallPlanUpdated = true } if _, err := o.client.OperatorsV1alpha1().InstallPlans(plan.GetNamespace()).UpdateStatus(plan); err != nil { diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index e07bf5a9d9..dfce328153 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -60,15 +60,15 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { bundle, key, err := e.querier.FindReplacement(op.Version(), op.Identifier(), op.SourceInfo().Package, op.SourceInfo().Channel, op.SourceInfo().Catalog) if err != nil || bundle == nil { - if bundle.BundlePath != "" { - e.gen.AddPendingOperator(LaunchBundleImageInfo{ - operatorSourceInfo: op.SourceInfo(), - image: bundle.BundlePath, - bundle: bundle, - }) - } continue } + if bundle.BundlePath != "" { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: op.SourceInfo(), + image: bundle.BundlePath, + bundle: bundle, + }) + } o, err := NewOperatorFromBundle(bundle, op.SourceInfo().StartingCSV, *key) if err != nil { @@ -90,29 +90,20 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] var err error if s.StartingCSV != "" { bundle, key, err = e.querier.FindBundle(s.Package, s.Channel, s.StartingCSV, s.Catalog) - if bundle.BundlePath != "" { - e.gen.AddPendingOperator(LaunchBundleImageInfo{ - operatorSourceInfo: &s, - image: bundle.BundlePath, - bundle: bundle, - }) - continue - } } else { bundle, key, err = e.querier.FindLatestBundle(s.Package, s.Channel, s.Catalog) - if bundle != nil && bundle.BundlePath != "" { - e.gen.AddPendingOperator(LaunchBundleImageInfo{ - operatorSourceInfo: &s, - image: bundle.BundlePath, - bundle: bundle, - }) - continue - } } if err != nil { // TODO: log or collect warnings return errors.Wrapf(err, "%s not found", s) } + if bundle.BundlePath != "" { + e.gen.AddPendingOperator(LaunchBundleImageInfo{ + operatorSourceInfo: &s, + image: bundle.BundlePath, + bundle: bundle, + }) + } o, err := NewOperatorFromBundle(bundle, s.StartingCSV, *key) if err != nil { diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index 87dc789b21..4df784ff13 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -6,15 +6,11 @@ import ( "fmt" "time" - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" - "github.com/operator-framework/operator-registry/pkg/configmap" - "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1" @@ -143,46 +139,12 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier // allow other operators to be processed first, then process ones that require copying data out of image bundleLookups := []*v1alpha1.BundleLookup{} - // prune operators that have in progress bundle image jobs - for bundleImageInfo := range gen.PendingOperators() { - // TODO: this is not ideal... - ips, err := r.listInstallPlans(namespace) - if err != nil { - return nil, nil, nil, err - } - for _, ip := range ips { - for _, lookup := range ip.Status.BundleLookups { - if lookup.Image == bundleImageInfo.image { - logrus.Debugf("found existing install plan, skipping bundle image %v", lookup.Image) - gen.RemovePendingOperator(bundleImageInfo) - } - } - } - } - for bundleImageInfo := range gen.PendingOperators() { // TODO: switch image to standalone image, but this image can be used upstream as well // change to use configmapRegistryImage //configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:latest", r.operatorNamespace) - configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/jpeeler/bundle-init-image:latest", r.operatorNamespace) - if err != nil { - return nil, nil, nil, err - } - logrus.Infof("Launched bundle job for image %v", bundleImageInfo.image) - bundleLookups = append(bundleLookups, &v1alpha1.BundleLookup{ - BundleJob: &v1alpha1.BundleJob{ - // job condition and completion time will be filled out later (installplan sync) - Name: job.GetName(), - Namespace: job.GetNamespace(), - }, - ConfigMapRef: &v1alpha1.ConfigMapResourceReference{ - Name: configmap.GetName(), - Namespace: configmap.GetNamespace(), - UID: configmap.GetUID(), - ResourceVersion: configmap.GetResourceVersion(), - }, Image: bundleImageInfo.image, BundleFromRegistry: bundleImageInfo.bundle, CatalogName: bundleImageInfo.operatorSourceInfo.Catalog.Name, diff --git a/test/e2e/installplan_e2e_test.go b/test/e2e/installplan_e2e_test.go index 39a2d4aaf1..70ba6ae768 100644 --- a/test/e2e/installplan_e2e_test.go +++ b/test/e2e/installplan_e2e_test.go @@ -2605,25 +2605,10 @@ func TestInstallPlanFromBundleImage(t *testing.T) { cleanupSubscription := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, catalogSourceName, "kiali", stableChannel, "", v1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionStateAny) - //subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(t, err) require.NotNil(t, subscription) - //installPlanName := subscription.Status.Install.Name - - // until subscription references are fixed... -TRYAGAIN: - var installPlanName string - ips, err := crc.OperatorsV1alpha1().InstallPlans(testNamespace).List(metav1.ListOptions{}) - require.NoError(t, err) - for _, ip := range ips.Items { - if ip.GetOwnerReferences()[0].Name == subscriptionName { - installPlanName = ip.GetName() - } - } - if installPlanName == "" { - goto TRYAGAIN - } + installPlanName := subscription.Status.Install.Name // get InstallPlan fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed, v1alpha1.InstallPlanPhaseComplete)) @@ -2640,7 +2625,8 @@ TRYAGAIN: registry.ResourceKey{Name: operatorName, Kind: "ClusterRole"}: {}, registry.ResourceKey{Name: operatorName, Kind: "ClusterRoleBinding"}: {}, } - require.Equal(t, len(expectedSteps), len(fetchedInstallPlan.Status.Plan), "number of expected steps does not match installed") + + require.Equal(t, len(expectedSteps), len(fetchedInstallPlan.Status.Plan), "number of expected steps does not match installed: %v", fetchedInstallPlan.Status.Plan) for _, step := range fetchedInstallPlan.Status.Plan { key := registry.ResourceKey{ @@ -2650,7 +2636,6 @@ TRYAGAIN: for expected := range expectedSteps { if strings.HasPrefix(key.Name, expected.Name) && key.Kind == expected.Kind { delete(expectedSteps, expected) - break } else { t.Logf("%v, %v: %v && %v", key, expected, strings.HasPrefix(key.Name, expected.Name), key.Kind == expected.Kind) } From b1bca97edf35dbed1b3386709ce64670431d0098 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Sat, 2 Nov 2019 12:56:04 -0400 Subject: [PATCH 12/12] feat(bundleimage): resolve bundle images --- go.mod | 4 - go.sum | 69 ---------- pkg/api/apis/operators/installplan_types.go | 20 +++ .../operators/v1alpha1/installplan_types.go | 14 +- .../v1alpha1/zz_generated.conversion.go | 129 ++++++++++++++++-- .../v1alpha1/zz_generated.deepcopy.go | 57 ++++++++ .../apis/operators/zz_generated.deepcopy.go | 57 ++++++++ pkg/controller/operators/catalog/operator.go | 32 +---- .../operators/catalog/subscriptions_test.go | 8 +- pkg/controller/registry/resolver/evolver.go | 23 +--- .../registry/resolver/generation.go | 3 +- .../registry/resolver/generation_test.go | 14 +- pkg/controller/registry/resolver/resolver.go | 52 +++---- .../registry/resolver/resolver_test.go | 16 ++- pkg/controller/registry/resolver/steps.go | 8 +- pkg/fakes/fake_resolver.go | 43 +++--- .../pkg/configmap/configmap.go | 96 ++----------- vendor/modules.txt | 9 +- 18 files changed, 353 insertions(+), 301 deletions(-) diff --git a/go.mod b/go.mod index 10bb4ef47f..ff74410be5 100644 --- a/go.mod +++ b/go.mod @@ -24,11 +24,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b -<<<<<<< ours github.com/operator-framework/operator-registry v1.5.3 -======= - github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c ->>>>>>> theirs github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 github.com/sirupsen/logrus v1.4.2 diff --git a/go.sum b/go.sum index e44ea659d6..4f84d291dd 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= -bou.ke/monkey v1.0.1 h1:zEMLInw9xvNakzUUPjfS4Ds6jYPqCFx3m7bRmG5NH2U= bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= 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= @@ -17,7 +16,6 @@ github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= @@ -25,7 +23,6 @@ github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.0.1 h1:iLrQrdwjDd52kHDA5op2UBJFjmOb9g+7scBan4RN8F0= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -62,7 +59,6 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -83,9 +79,7 @@ github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coredns/corefile-migration v1.0.2/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= -github.com/coreos/bbolt v1.3.1-coreos.6 h1:uTXKg9gY70s9jMAKdfljFQcuh4e/BXOM+V+d00KFj3A= github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible h1:KjVWqrZ5U0wa3CxY2AxlH6/UcB+PK2td1DcsYhA+HRs= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.15+incompatible h1:+9RjdC18gMxNQVvSiXvObLu29mOFmkgdsB4cRTlV+EE= github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -97,7 +91,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a h1:W8b4lQ4tFF21aspRGoBuCNV6V2fFJBF+pm1J6OY8Lys= github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -120,12 +113,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -153,7 +144,6 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -219,7 +209,6 @@ github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhD github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= 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 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -227,7 +216,6 @@ github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHX github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= 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 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -237,7 +225,6 @@ github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -248,7 +235,6 @@ github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAO github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/cadvisor v0.34.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= @@ -277,25 +263,20 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.9.4 h1:5xLhQjsk4zqPf9EHCrja2qFZMx+yBqkO3XgJ14bNnU0= github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db h1:UxmGBzaBcWDQuQh9E1iT1dWKQFbizZ+SpTd1EL4MSqs= github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -304,7 +285,6 @@ github.com/heketi/heketi v9.0.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7 github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI= github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/heketi/utils v0.0.0-20170317161834-435bc5bdfa64/go.mod h1:RYlF4ghFZPPmk2TC5REt5OFwvfb6lzxFWrTWB+qs28s= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= @@ -315,12 +295,9 @@ github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80s github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -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/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -333,16 +310,13 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= @@ -407,13 +381,10 @@ github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -425,24 +396,12 @@ github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b h1:E++qQ7W1/Ed github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b/go.mod h1:6rzn+JTr7+WYS2E1TExP4gByoABxMznR6y2SnUIkmxk= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/operator-framework/operator-registry v1.4.0 h1:yhI7ZeF6d7G588i2egoFjgGi1eXhaU1aL0GMEMDuS/4= -github.com/operator-framework/operator-registry v1.4.0/go.mod h1:3nJcOSX6TKPpAbmGOAVvDxakZWgccyF0WgiJsKjPAzQ= -github.com/operator-framework/operator-registry v1.5.1 h1:8ruUOG6IBDVTAXYWKsv6hwr4yv/0SFPFPAYGCpcv97E= -github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -<<<<<<< ours github.com/operator-framework/operator-registry v1.5.3 h1:az83WDwgB+tHsmVn+tFq72yQBbaUAye8e4+KkDQmzLs= github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -======= -github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c h1:ozT20B/o6SfMeZr2kjGVvSviTYh0xJ4fHxRPjAfvk7E= -github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= ->>>>>>> theirs -github.com/otiai10/copy v1.0.1 h1:gtBjD8aq4nychvRZ2CyJvFWAw0aja+VHazDdruZKGZA= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776 h1:o59bHXu8Ejas8Kq6pjoVJQ9/neN66SM8AKh6wI42BBs= github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw= -github.com/otiai10/mint v1.2.4 h1:DxYL0itZyPaR5Z9HILdxSoHx+gNs6Yx+neOGS3IVUk0= github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -459,25 +418,17 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20190104105734-b1c43a6df3ae h1:iq3e1tH4dCzdqscIkWimcnzYt6Pkz0zOzHSgV9cb5DE= -github.com/prometheus/common v0.0.0-20190104105734-b1c43a6df3ae/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74 h1:d1Xoc24yp/pXmWl2leBiBA+Tptce6cQsA+MMx/nOOcY= -github.com/prometheus/procfs v0.0.0-20190104112138-b1a0a9a36d74/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= @@ -490,7 +441,6 @@ github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvf github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sclevine/spec v1.2.0 h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -502,10 +452,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= @@ -523,18 +471,14 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= @@ -543,9 +487,7 @@ github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= 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/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 h1:MPPkRncZLN9Kh4MEFmbnK4h3BD7AUmskWv2+EeZJCCs= github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -576,9 +518,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2 h1:y102fOLFqhV41b+4GPiJoa0k/x+pJcEi2/HB1Y5T6fU= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495 h1:I6A9Ag9FpEKOjcKrRNjQkPHawoXIhKyTGfvvjFAiiAk= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -609,7 +549,6 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -679,18 +618,14 @@ golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDq gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/gonum v0.0.0-20190710053202-4340aa3071a0 h1:2qZ38BsejXrhuetzb8UxucqrWDZKjypFSZA82hLCpZ4= gonum.org/v1/gonum v0.0.0-20190710053202-4340aa3071a0/go.mod h1:03dgh78c4UvU1WksguQ/lvJQXbezKQGJSrwwRq5MraQ= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -710,10 +645,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= @@ -725,7 +658,6 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -765,7 +697,6 @@ k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKO k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ= k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= diff --git a/pkg/api/apis/operators/installplan_types.go b/pkg/api/apis/operators/installplan_types.go index 447fd90a0f..0dab15a9ce 100644 --- a/pkg/api/apis/operators/installplan_types.go +++ b/pkg/api/apis/operators/installplan_types.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -83,6 +84,7 @@ type InstallPlanStatus struct { CatalogSources []string Plan []*Step AttenuatedServiceAccountRef *corev1.ObjectReference + BundleLookups []*BundleLookup `json:"bundleLookup,omitempty"` } // InstallPlanCondition represents the overall status of the execution of @@ -157,6 +159,24 @@ type Step struct { Status StepStatus } +// BundleJob tracks the job status for a given bundle +type BundleJob struct { + Name string `json:"name, omitempty"` + Namespace string `json:"namespace, omitempty"` + Condition batchv1.JobConditionType `json:"condition, omitempty"` + CompletionTime *metav1.Time `json:"completionTime, omitempty"` +} + +// BundleLookup serves as accounting for tracking a bundle data lookup +type BundleLookup struct { + BundleJob *BundleJob `json:"bundleJob"` + ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` + Image string `json:"image"` + CatalogName string `json:"catalogName"` + CatalogNamespace string `json:"catalogNamespace"` + Replaces string `json:"replaces"` +} + // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps // matches those in the InstallPlanStatus. func (s *InstallPlanStatus) CSVManifestsMatch(steps []*Step) bool { diff --git a/pkg/api/apis/operators/v1alpha1/installplan_types.go b/pkg/api/apis/operators/v1alpha1/installplan_types.go index 0a52f45c66..47b646bc1c 100644 --- a/pkg/api/apis/operators/v1alpha1/installplan_types.go +++ b/pkg/api/apis/operators/v1alpha1/installplan_types.go @@ -7,8 +7,6 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/operator-framework/operator-registry/pkg/api" ) const ( @@ -176,12 +174,12 @@ type BundleJob struct { // BundleLookup serves as accounting for tracking a bundle data lookup type BundleLookup struct { - BundleJob *BundleJob `json:"bundleJob"` - ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` - Image string `json:"image"` - BundleFromRegistry *api.Bundle `json:"bundleFromRegistry"` - CatalogName string `json:"catalogName"` - CatalogNamespace string `json:"catalogNamespace"` + BundleJob *BundleJob `json:"bundleJob"` + ConfigMapRef *ConfigMapResourceReference `json:"configMapRef"` + Image string `json:"image"` + CatalogName string `json:"catalogName"` + CatalogNamespace string `json:"catalogNamespace"` + Replaces string `json:"replaces"` } // ManifestsMatch returns true if the CSV manifests in the StepResources of the given list of steps diff --git a/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go b/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go index 208bd436b4..35715f1c1e 100644 --- a/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go +++ b/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go @@ -25,8 +25,9 @@ import ( unsafe "unsafe" operators "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators" + v1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" types "k8s.io/apimachinery/pkg/types" @@ -89,6 +90,26 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*BundleJob)(nil), (*operators.BundleJob)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleJob_To_operators_BundleJob(a.(*BundleJob), b.(*operators.BundleJob), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*operators.BundleJob)(nil), (*BundleJob)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_operators_BundleJob_To_v1alpha1_BundleJob(a.(*operators.BundleJob), b.(*BundleJob), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*BundleLookup)(nil), (*operators.BundleLookup)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleLookup_To_operators_BundleLookup(a.(*BundleLookup), b.(*operators.BundleLookup), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*operators.BundleLookup)(nil), (*BundleLookup)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_operators_BundleLookup_To_v1alpha1_BundleLookup(a.(*operators.BundleLookup), b.(*BundleLookup), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*CRDDescription)(nil), (*operators.CRDDescription)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_CRDDescription_To_operators_CRDDescription(a.(*CRDDescription), b.(*operators.CRDDescription), scope) }); err != nil { @@ -600,6 +621,62 @@ func Convert_operators_AppLink_To_v1alpha1_AppLink(in *operators.AppLink, out *A return autoConvert_operators_AppLink_To_v1alpha1_AppLink(in, out, s) } +func autoConvert_v1alpha1_BundleJob_To_operators_BundleJob(in *BundleJob, out *operators.BundleJob, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + out.Condition = v1.JobConditionType(in.Condition) + out.CompletionTime = (*metav1.Time)(unsafe.Pointer(in.CompletionTime)) + return nil +} + +// Convert_v1alpha1_BundleJob_To_operators_BundleJob is an autogenerated conversion function. +func Convert_v1alpha1_BundleJob_To_operators_BundleJob(in *BundleJob, out *operators.BundleJob, s conversion.Scope) error { + return autoConvert_v1alpha1_BundleJob_To_operators_BundleJob(in, out, s) +} + +func autoConvert_operators_BundleJob_To_v1alpha1_BundleJob(in *operators.BundleJob, out *BundleJob, s conversion.Scope) error { + out.Name = in.Name + out.Namespace = in.Namespace + out.Condition = v1.JobConditionType(in.Condition) + out.CompletionTime = (*metav1.Time)(unsafe.Pointer(in.CompletionTime)) + return nil +} + +// Convert_operators_BundleJob_To_v1alpha1_BundleJob is an autogenerated conversion function. +func Convert_operators_BundleJob_To_v1alpha1_BundleJob(in *operators.BundleJob, out *BundleJob, s conversion.Scope) error { + return autoConvert_operators_BundleJob_To_v1alpha1_BundleJob(in, out, s) +} + +func autoConvert_v1alpha1_BundleLookup_To_operators_BundleLookup(in *BundleLookup, out *operators.BundleLookup, s conversion.Scope) error { + out.BundleJob = (*operators.BundleJob)(unsafe.Pointer(in.BundleJob)) + out.ConfigMapRef = (*operators.ConfigMapResourceReference)(unsafe.Pointer(in.ConfigMapRef)) + out.Image = in.Image + out.CatalogName = in.CatalogName + out.CatalogNamespace = in.CatalogNamespace + out.Replaces = in.Replaces + return nil +} + +// Convert_v1alpha1_BundleLookup_To_operators_BundleLookup is an autogenerated conversion function. +func Convert_v1alpha1_BundleLookup_To_operators_BundleLookup(in *BundleLookup, out *operators.BundleLookup, s conversion.Scope) error { + return autoConvert_v1alpha1_BundleLookup_To_operators_BundleLookup(in, out, s) +} + +func autoConvert_operators_BundleLookup_To_v1alpha1_BundleLookup(in *operators.BundleLookup, out *BundleLookup, s conversion.Scope) error { + out.BundleJob = (*BundleJob)(unsafe.Pointer(in.BundleJob)) + out.ConfigMapRef = (*ConfigMapResourceReference)(unsafe.Pointer(in.ConfigMapRef)) + out.Image = in.Image + out.CatalogName = in.CatalogName + out.CatalogNamespace = in.CatalogNamespace + out.Replaces = in.Replaces + return nil +} + +// Convert_operators_BundleLookup_To_v1alpha1_BundleLookup is an autogenerated conversion function. +func Convert_operators_BundleLookup_To_v1alpha1_BundleLookup(in *operators.BundleLookup, out *BundleLookup, s conversion.Scope) error { + return autoConvert_operators_BundleLookup_To_v1alpha1_BundleLookup(in, out, s) +} + func autoConvert_v1alpha1_CRDDescription_To_operators_CRDDescription(in *CRDDescription, out *operators.CRDDescription, s conversion.Scope) error { out.Name = in.Name out.Version = in.Version @@ -852,7 +929,7 @@ func autoConvert_v1alpha1_ClusterServiceVersionSpec_To_operators_ClusterServiceV if err := Convert_v1alpha1_APIServiceDefinitions_To_operators_APIServiceDefinitions(&in.APIServiceDefinitions, &out.APIServiceDefinitions, s); err != nil { return err } - out.NativeAPIs = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.NativeAPIs)) + out.NativeAPIs = *(*[]metav1.GroupVersionKind)(unsafe.Pointer(&in.NativeAPIs)) out.MinKubeVersion = in.MinKubeVersion out.DisplayName = in.DisplayName out.Description = in.Description @@ -867,7 +944,7 @@ func autoConvert_v1alpha1_ClusterServiceVersionSpec_To_operators_ClusterServiceV out.Replaces = in.Replaces out.Labels = *(*map[string]string)(unsafe.Pointer(&in.Labels)) out.Annotations = *(*map[string]string)(unsafe.Pointer(&in.Annotations)) - out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) return nil } @@ -888,7 +965,7 @@ func autoConvert_operators_ClusterServiceVersionSpec_To_v1alpha1_ClusterServiceV if err := Convert_operators_APIServiceDefinitions_To_v1alpha1_APIServiceDefinitions(&in.APIServiceDefinitions, &out.APIServiceDefinitions, s); err != nil { return err } - out.NativeAPIs = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.NativeAPIs)) + out.NativeAPIs = *(*[]metav1.GroupVersionKind)(unsafe.Pointer(&in.NativeAPIs)) out.MinKubeVersion = in.MinKubeVersion out.DisplayName = in.DisplayName out.Description = in.Description @@ -903,7 +980,7 @@ func autoConvert_operators_ClusterServiceVersionSpec_To_v1alpha1_ClusterServiceV out.Replaces = in.Replaces out.Labels = *(*map[string]string)(unsafe.Pointer(&in.Labels)) out.Annotations = *(*map[string]string)(unsafe.Pointer(&in.Annotations)) - out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) return nil } @@ -1160,7 +1237,17 @@ func Convert_operators_InstallPlanCondition_To_v1alpha1_InstallPlanCondition(in func autoConvert_v1alpha1_InstallPlanList_To_operators_InstallPlanList(in *InstallPlanList, out *operators.InstallPlanList, s conversion.Scope) error { out.ListMeta = in.ListMeta - out.Items = *(*[]operators.InstallPlan)(unsafe.Pointer(&in.Items)) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]operators.InstallPlan, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_InstallPlan_To_operators_InstallPlan(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } return nil } @@ -1171,7 +1258,17 @@ func Convert_v1alpha1_InstallPlanList_To_operators_InstallPlanList(in *InstallPl func autoConvert_operators_InstallPlanList_To_v1alpha1_InstallPlanList(in *operators.InstallPlanList, out *InstallPlanList, s conversion.Scope) error { out.ListMeta = in.ListMeta - out.Items = *(*[]InstallPlan)(unsafe.Pointer(&in.Items)) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]InstallPlan, len(*in)) + for i := range *in { + if err := Convert_operators_InstallPlan_To_v1alpha1_InstallPlan(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } return nil } @@ -1239,6 +1336,7 @@ func autoConvert_v1alpha1_InstallPlanStatus_To_operators_InstallPlanStatus(in *I out.Conditions = *(*[]operators.InstallPlanCondition)(unsafe.Pointer(&in.Conditions)) out.CatalogSources = *(*[]string)(unsafe.Pointer(&in.CatalogSources)) out.Plan = *(*[]*operators.Step)(unsafe.Pointer(&in.Plan)) + out.BundleLookups = *(*[]*operators.BundleLookup)(unsafe.Pointer(&in.BundleLookups)) out.AttenuatedServiceAccountRef = (*corev1.ObjectReference)(unsafe.Pointer(in.AttenuatedServiceAccountRef)) return nil } @@ -1254,6 +1352,7 @@ func autoConvert_operators_InstallPlanStatus_To_v1alpha1_InstallPlanStatus(in *o out.CatalogSources = *(*[]string)(unsafe.Pointer(&in.CatalogSources)) out.Plan = *(*[]*Step)(unsafe.Pointer(&in.Plan)) out.AttenuatedServiceAccountRef = (*corev1.ObjectReference)(unsafe.Pointer(in.AttenuatedServiceAccountRef)) + out.BundleLookups = *(*[]*BundleLookup)(unsafe.Pointer(&in.BundleLookups)) return nil } @@ -1514,7 +1613,7 @@ func Convert_operators_Subscription_To_v1alpha1_Subscription(in *operators.Subsc func autoConvert_v1alpha1_SubscriptionCatalogHealth_To_operators_SubscriptionCatalogHealth(in *SubscriptionCatalogHealth, out *operators.SubscriptionCatalogHealth, s conversion.Scope) error { out.CatalogSourceRef = (*corev1.ObjectReference)(unsafe.Pointer(in.CatalogSourceRef)) - out.LastUpdated = (*v1.Time)(unsafe.Pointer(in.LastUpdated)) + out.LastUpdated = (*metav1.Time)(unsafe.Pointer(in.LastUpdated)) out.Healthy = in.Healthy return nil } @@ -1526,7 +1625,7 @@ func Convert_v1alpha1_SubscriptionCatalogHealth_To_operators_SubscriptionCatalog func autoConvert_operators_SubscriptionCatalogHealth_To_v1alpha1_SubscriptionCatalogHealth(in *operators.SubscriptionCatalogHealth, out *SubscriptionCatalogHealth, s conversion.Scope) error { out.CatalogSourceRef = (*corev1.ObjectReference)(unsafe.Pointer(in.CatalogSourceRef)) - out.LastUpdated = (*v1.Time)(unsafe.Pointer(in.LastUpdated)) + out.LastUpdated = (*metav1.Time)(unsafe.Pointer(in.LastUpdated)) out.Healthy = in.Healthy return nil } @@ -1541,8 +1640,8 @@ func autoConvert_v1alpha1_SubscriptionCondition_To_operators_SubscriptionConditi out.Status = corev1.ConditionStatus(in.Status) out.Reason = in.Reason out.Message = in.Message - out.LastHeartbeatTime = (*v1.Time)(unsafe.Pointer(in.LastHeartbeatTime)) - out.LastTransitionTime = (*v1.Time)(unsafe.Pointer(in.LastTransitionTime)) + out.LastHeartbeatTime = (*metav1.Time)(unsafe.Pointer(in.LastHeartbeatTime)) + out.LastTransitionTime = (*metav1.Time)(unsafe.Pointer(in.LastTransitionTime)) return nil } @@ -1556,8 +1655,8 @@ func autoConvert_operators_SubscriptionCondition_To_v1alpha1_SubscriptionConditi out.Status = corev1.ConditionStatus(in.Status) out.Reason = in.Reason out.Message = in.Message - out.LastHeartbeatTime = (*v1.Time)(unsafe.Pointer(in.LastHeartbeatTime)) - out.LastTransitionTime = (*v1.Time)(unsafe.Pointer(in.LastTransitionTime)) + out.LastHeartbeatTime = (*metav1.Time)(unsafe.Pointer(in.LastHeartbeatTime)) + out.LastTransitionTime = (*metav1.Time)(unsafe.Pointer(in.LastTransitionTime)) return nil } @@ -1567,7 +1666,7 @@ func Convert_operators_SubscriptionCondition_To_v1alpha1_SubscriptionCondition(i } func autoConvert_v1alpha1_SubscriptionConfig_To_operators_SubscriptionConfig(in *SubscriptionConfig, out *operators.SubscriptionConfig, s conversion.Scope) error { - out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) out.Tolerations = *(*[]corev1.Toleration)(unsafe.Pointer(&in.Tolerations)) out.Resources = in.Resources @@ -1584,7 +1683,7 @@ func Convert_v1alpha1_SubscriptionConfig_To_operators_SubscriptionConfig(in *Sub } func autoConvert_operators_SubscriptionConfig_To_v1alpha1_SubscriptionConfig(in *operators.SubscriptionConfig, out *SubscriptionConfig, s conversion.Scope) error { - out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector)) + out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector)) out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector)) out.Tolerations = *(*[]corev1.Toleration)(unsafe.Pointer(&in.Tolerations)) out.Resources = in.Resources diff --git a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go index b950b42f10..dcbca2159a 100644 --- a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go @@ -162,6 +162,52 @@ func (in *AppLink) DeepCopy() *AppLink { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleJob) DeepCopyInto(out *BundleJob) { + *out = *in + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleJob. +func (in *BundleJob) DeepCopy() *BundleJob { + if in == nil { + return nil + } + out := new(BundleJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleLookup) DeepCopyInto(out *BundleLookup) { + *out = *in + if in.BundleJob != nil { + in, out := &in.BundleJob, &out.BundleJob + *out = new(BundleJob) + (*in).DeepCopyInto(*out) + } + if in.ConfigMapRef != nil { + in, out := &in.ConfigMapRef, &out.ConfigMapRef + *out = new(ConfigMapResourceReference) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleLookup. +func (in *BundleLookup) DeepCopy() *BundleLookup { + if in == nil { + return nil + } + out := new(BundleLookup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CRDDescription) DeepCopyInto(out *CRDDescription) { *out = *in @@ -777,6 +823,17 @@ func (in *InstallPlanStatus) DeepCopyInto(out *InstallPlanStatus) { } } } + if in.BundleLookups != nil { + in, out := &in.BundleLookups, &out.BundleLookups + *out = make([]*BundleLookup, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(BundleLookup) + (*in).DeepCopyInto(*out) + } + } + } if in.AttenuatedServiceAccountRef != nil { in, out := &in.AttenuatedServiceAccountRef, &out.AttenuatedServiceAccountRef *out = new(corev1.ObjectReference) diff --git a/pkg/api/apis/operators/zz_generated.deepcopy.go b/pkg/api/apis/operators/zz_generated.deepcopy.go index 52ebe586b9..19ee9a149f 100644 --- a/pkg/api/apis/operators/zz_generated.deepcopy.go +++ b/pkg/api/apis/operators/zz_generated.deepcopy.go @@ -162,6 +162,52 @@ func (in *AppLink) DeepCopy() *AppLink { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleJob) DeepCopyInto(out *BundleJob) { + *out = *in + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleJob. +func (in *BundleJob) DeepCopy() *BundleJob { + if in == nil { + return nil + } + out := new(BundleJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleLookup) DeepCopyInto(out *BundleLookup) { + *out = *in + if in.BundleJob != nil { + in, out := &in.BundleJob, &out.BundleJob + *out = new(BundleJob) + (*in).DeepCopyInto(*out) + } + if in.ConfigMapRef != nil { + in, out := &in.ConfigMapRef, &out.ConfigMapRef + *out = new(ConfigMapResourceReference) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleLookup. +func (in *BundleLookup) DeepCopy() *BundleLookup { + if in == nil { + return nil + } + out := new(BundleLookup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CRDDescription) DeepCopyInto(out *CRDDescription) { *out = *in @@ -782,6 +828,17 @@ func (in *InstallPlanStatus) DeepCopyInto(out *InstallPlanStatus) { *out = new(corev1.ObjectReference) **out = **in } + if in.BundleLookups != nil { + in, out := &in.BundleLookups, &out.BundleLookups + *out = make([]*BundleLookup, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(BundleLookup) + (*in).DeepCopyInto(*out) + } + } + } return } diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 62dc7353ea..d6140e381c 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -136,7 +136,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo client: crClient, lister: lister, namespace: operatorNamespace, - resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient, opClient.KubernetesInterface(), operatorNamespace), + resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient, opClient.KubernetesInterface()), catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(), subQueueSet: queueinformer.NewEmptyResourceQueueSet(), ipQueueSet: queueinformer.NewEmptyResourceQueueSet(), @@ -1072,37 +1072,13 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) } // extract data from configmap and write to install plan - manifest, err := o.bundleLoader.Load(configmap) + bundle, err := o.bundleLoader.Load(configmap) if err != nil { return false, err } - // combine data from the bundle image into what's already known from the registry - bundleLookup.BundleFromRegistry.CsvName = manifest.Bundle.Name - bundleLookup.BundleFromRegistry.PackageName = manifest.Bundle.Package - bundleLookup.BundleFromRegistry.ChannelName = manifest.Bundle.Channel - _, jsonCSV, _, err := manifest.Bundle.Serialize() - if err != nil { - return false, fmt.Errorf("serialize failed: %s", err.Error()) - } - bundleLookup.BundleFromRegistry.CsvJson = string(jsonCSV) - bundleLookup.BundleFromRegistry.Object = []string{string(jsonCSV)} - for _, item := range manifest.Bundle.Objects { - bytes, err := item.MarshalJSON() - if err != nil { - return false, fmt.Errorf("marshall failed: %v", err) - } - bundleLookup.BundleFromRegistry.Object = append(bundleLookup.BundleFromRegistry.Object, string(bytes)) - } - - var olmCSV v1alpha1.ClusterServiceVersion - err = json.Unmarshal(jsonCSV, &olmCSV) - if err != nil { - return false, fmt.Errorf("csv retrieval failed: %s", err.Error()) - } - // TODO: refactor with resolver code (and call the subscription stuff too) - bundleSteps, err := resolver.NewStepResourceFromBundle(bundleLookup.BundleFromRegistry, plan.GetNamespace(), olmCSV.Spec.Replaces, bundleLookup.CatalogName, bundleLookup.CatalogNamespace) + bundleSteps, err := resolver.NewStepResourceFromBundle(bundle, plan.GetNamespace(), bundleLookup.Replaces, bundleLookup.CatalogName, bundleLookup.CatalogNamespace) if err != nil { return false, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) } @@ -1110,7 +1086,7 @@ func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) // TODO: could this add duplicate steps? for _, s := range bundleSteps { plan.Status.Plan = append(plan.Status.Plan, &v1alpha1.Step{ - Resolving: olmCSV.GetName(), + Resolving: bundle.CsvName, Resource: s, Status: v1alpha1.StepStatusUnknown, }) diff --git a/pkg/controller/operators/catalog/subscriptions_test.go b/pkg/controller/operators/catalog/subscriptions_test.go index 49bd070666..269791f3d4 100644 --- a/pkg/controller/operators/catalog/subscriptions_test.go +++ b/pkg/controller/operators/catalog/subscriptions_test.go @@ -819,8 +819,8 @@ func TestSyncSubscriptions(t *testing.T) { o.sourcesLastUpdate.Set(tt.fields.sourcesLastUpdate.Time) o.resolver = &fakes.FakeResolver{ - ResolveStepsStub: func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) { - return tt.fields.resolveSteps, tt.fields.resolveSubs, tt.fields.resolveErr + ResolveStepsStub: func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) { + return tt.fields.resolveSteps, nil, tt.fields.resolveSubs, tt.fields.resolveErr }, } @@ -951,7 +951,7 @@ func BenchmarkSyncResolvingNamespace(b *testing.B) { }, }, resolver: &fakes.FakeResolver{ - ResolveStepsStub: func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) { + ResolveStepsStub: func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) { steps := []*v1alpha1.Step{ { Resolving: "csv.v.2", @@ -987,7 +987,7 @@ func BenchmarkSyncResolvingNamespace(b *testing.B) { }, } - return steps, subs, nil + return steps, nil, subs, nil }, }, }, diff --git a/pkg/controller/registry/resolver/evolver.go b/pkg/controller/registry/resolver/evolver.go index dfce328153..2ae839e1b5 100644 --- a/pkg/controller/registry/resolver/evolver.go +++ b/pkg/controller/registry/resolver/evolver.go @@ -66,8 +66,9 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { e.gen.AddPendingOperator(LaunchBundleImageInfo{ operatorSourceInfo: op.SourceInfo(), image: bundle.BundlePath, - bundle: bundle, + replaces: op.Identifier(), }) + return nil } o, err := NewOperatorFromBundle(bundle, op.SourceInfo().StartingCSV, *key) @@ -97,22 +98,13 @@ func (e *NamespaceGenerationEvolver) addNewOperators(add map[OperatorSourceInfo] // TODO: log or collect warnings return errors.Wrapf(err, "%s not found", s) } - if bundle.BundlePath != "" { - e.gen.AddPendingOperator(LaunchBundleImageInfo{ - operatorSourceInfo: &s, - image: bundle.BundlePath, - bundle: bundle, - }) - } o, err := NewOperatorFromBundle(bundle, s.StartingCSV, *key) if err != nil { return errors.Wrap(err, "error parsing bundle") } if err := e.gen.AddOperator(o); err != nil { - if err != nil { - return errors.Wrap(err, "error calculating generation changes due to new bundle") - } + return errors.Wrap(err, "error calculating generation changes due to new bundle") } } return nil @@ -137,15 +129,6 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error { // attempt to find a bundle that provides that api if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog); err == nil { - if bundle.BundlePath != "" { - e.gen.AddPendingOperator(LaunchBundleImageInfo{ - operatorSourceInfo: initialSource, - image: bundle.BundlePath, - bundle: bundle, - }) - return nil - } - // add a bundle that provides the api to the generation o, err := NewOperatorFromBundle(bundle, "", *key) if err != nil { diff --git a/pkg/controller/registry/resolver/generation.go b/pkg/controller/registry/resolver/generation.go index 610f78020a..96fc10154c 100644 --- a/pkg/controller/registry/resolver/generation.go +++ b/pkg/controller/registry/resolver/generation.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" - "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/registry" ) @@ -24,7 +23,7 @@ type Generation interface { type LaunchBundleImageInfo struct { operatorSourceInfo *OperatorSourceInfo image string - bundle *api.Bundle + replaces string } type BundleImageSet map[LaunchBundleImageInfo]struct{} diff --git a/pkg/controller/registry/resolver/generation_test.go b/pkg/controller/registry/resolver/generation_test.go index c927710da8..d84ca2a3cc 100644 --- a/pkg/controller/registry/resolver/generation_test.go +++ b/pkg/controller/registry/resolver/generation_test.go @@ -37,10 +37,11 @@ func TestNewGenerationFromCSVs(t *testing.T) { }, }, want: &NamespaceGeneration{ - providedAPIs: EmptyAPIOwnerSet(), - requiredAPIs: EmptyAPIMultiOwnerSet(), - uncheckedAPIs: EmptyAPISet(), - missingAPIs: EmptyAPIMultiOwnerSet(), + pendingOperators: BundleImageSet{}, + providedAPIs: EmptyAPIOwnerSet(), + requiredAPIs: EmptyAPIMultiOwnerSet(), + uncheckedAPIs: EmptyAPISet(), + missingAPIs: EmptyAPIMultiOwnerSet(), }, }, { @@ -76,6 +77,7 @@ func TestNewGenerationFromCSVs(t *testing.T) { }, }, want: &NamespaceGeneration{ + pendingOperators: BundleImageSet{}, providedAPIs: map[opregistry.APIKey]OperatorSurface{ {Group: "g", Version: "v1", Kind: "APIKind", Plural: "apikinds"}: &Operator{ name: "operator.v1", @@ -136,7 +138,8 @@ func TestNewGenerationFromCSVs(t *testing.T) { }, }, want: &NamespaceGeneration{ - providedAPIs: EmptyAPIOwnerSet(), + pendingOperators: BundleImageSet{}, + providedAPIs: EmptyAPIOwnerSet(), requiredAPIs: map[opregistry.APIKey]OperatorSet{ {Group: "g", Version: "v1", Kind: "APIKind", Plural: "apikinds"}: map[string]OperatorSurface{ "operator.v1": &Operator{ @@ -243,6 +246,7 @@ func TestNewGenerationFromCSVs(t *testing.T) { }, }, want: &NamespaceGeneration{ + pendingOperators: BundleImageSet{}, providedAPIs: map[opregistry.APIKey]OperatorSurface{ {Group: "g", Version: "v1", Kind: "APIOwnedKind", Plural: "apiownedkinds"}: &Operator{ name: "operator.v1", diff --git a/pkg/controller/registry/resolver/resolver.go b/pkg/controller/registry/resolver/resolver.go index 4df784ff13..2df8e5e8ad 100644 --- a/pkg/controller/registry/resolver/resolver.go +++ b/pkg/controller/registry/resolver/resolver.go @@ -24,24 +24,22 @@ type Resolver interface { } type OperatorsV1alpha1Resolver struct { - subLister v1alpha1listers.SubscriptionLister - csvLister v1alpha1listers.ClusterServiceVersionLister - ipLister v1alpha1listers.InstallPlanLister - client versioned.Interface - kubeclient kubernetes.Interface - operatorNamespace string + subLister v1alpha1listers.SubscriptionLister + csvLister v1alpha1listers.ClusterServiceVersionLister + ipLister v1alpha1listers.InstallPlanLister + client versioned.Interface + kubeclient kubernetes.Interface } var _ Resolver = &OperatorsV1alpha1Resolver{} -func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client versioned.Interface, kubeclient kubernetes.Interface, operatorNamespace string) *OperatorsV1alpha1Resolver { +func NewOperatorsV1alpha1Resolver(lister operatorlister.OperatorLister, client versioned.Interface, kubeclient kubernetes.Interface) *OperatorsV1alpha1Resolver { return &OperatorsV1alpha1Resolver{ - subLister: lister.OperatorsV1alpha1().SubscriptionLister(), - csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(), - ipLister: lister.OperatorsV1alpha1().InstallPlanLister(), - client: client, - kubeclient: kubeclient, - operatorNamespace: operatorNamespace, + subLister: lister.OperatorsV1alpha1().SubscriptionLister(), + csvLister: lister.OperatorsV1alpha1().ClusterServiceVersionLister(), + ipLister: lister.OperatorsV1alpha1().InstallPlanLister(), + client: client, + kubeclient: kubeclient, } } @@ -90,6 +88,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier // changes to persist to the cluster and write them out as `steps` steps := []*v1alpha1.Step{} updatedSubs := []*v1alpha1.Subscription{} + bundleLookups := []*v1alpha1.BundleLookup{} for name, op := range gen.Operators() { _, isAdded := add[*op.SourceInfo()] existingSubscription, subExists := subMap[*op.SourceInfo()] @@ -100,7 +99,7 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier } // add steps for any new bundle - if op.Bundle() != nil { + if op.Bundle() != nil && op.Bundle().BundlePath == "" { bundleSteps, err := NewStepResourceFromBundle(op.Bundle(), namespace, op.Replaces(), op.SourceInfo().Catalog.Name, op.SourceInfo().Catalog.Namespace) if err != nil { return nil, nil, nil, fmt.Errorf("failed to turn bundle into steps: %s", err.Error()) @@ -129,6 +128,15 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier } } + if op.Bundle() != nil && op.Bundle().BundlePath != "" { + bundleLookups = append(bundleLookups, &v1alpha1.BundleLookup{ + Image: op.Bundle().BundlePath, + CatalogName: op.SourceInfo().Catalog.Name, + CatalogNamespace: op.SourceInfo().Catalog.Namespace, + Replaces: op.Replaces(), + }) + } + // update existing subscriptions status if subExists && existingSubscription.Status.CurrentCSV != op.Identifier() { existingSubscription.Status.CurrentCSV = op.Identifier() @@ -136,22 +144,6 @@ func (r *OperatorsV1alpha1Resolver) ResolveSteps(namespace string, sourceQuerier } } - // allow other operators to be processed first, then process ones that require copying data out of image - bundleLookups := []*v1alpha1.BundleLookup{} - - for bundleImageInfo := range gen.PendingOperators() { - // TODO: switch image to standalone image, but this image can be used upstream as well - // change to use configmapRegistryImage - //configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:latest", r.operatorNamespace) - - bundleLookups = append(bundleLookups, &v1alpha1.BundleLookup{ - Image: bundleImageInfo.image, - BundleFromRegistry: bundleImageInfo.bundle, - CatalogName: bundleImageInfo.operatorSourceInfo.Catalog.Name, - CatalogNamespace: bundleImageInfo.operatorSourceInfo.Catalog.Namespace, - }) - } - return steps, bundleLookups, updatedSubs, nil } diff --git a/pkg/controller/registry/resolver/resolver_test.go b/pkg/controller/registry/resolver/resolver_test.go index 284fbf2da4..12effb014c 100644 --- a/pkg/controller/registry/resolver/resolver_test.go +++ b/pkg/controller/registry/resolver/resolver_test.go @@ -5,15 +5,17 @@ import ( "testing" "time" - "github.com/operator-framework/operator-registry/pkg/api" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + k8sfake "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/cache" + "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/api/apis/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake" @@ -381,9 +383,10 @@ func TestNamespaceResolver(t *testing.T) { lister := operatorlister.NewLister() lister.OperatorsV1alpha1().RegisterSubscriptionLister(namespace, informerFactory.Operators().V1alpha1().Subscriptions().Lister()) lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(namespace, informerFactory.Operators().V1alpha1().ClusterServiceVersions().Lister()) + kClientFake := k8sfake.NewSimpleClientset() - resolver := NewOperatorsV1alpha1Resolver(lister, clientFake) - steps, subs, err := resolver.ResolveSteps(namespace, tt.querier) + resolver := NewOperatorsV1alpha1Resolver(lister, clientFake, kClientFake) + steps, _, subs, err := resolver.ResolveSteps(namespace, tt.querier) require.Equal(t, tt.out.err, err) t.Logf("%#v", steps) RequireStepsEqual(t, expectedSteps, steps) @@ -450,14 +453,15 @@ func TestNamespaceResolverRBAC(t *testing.T) { for _, steps := range tt.out.steps { expectedSteps = append(expectedSteps, steps...) } + kClientFake := k8sfake.NewSimpleClientset() clientFake, informerFactory, _ := StartResolverInformers(namespace, stopc, tt.clusterState...) lister := operatorlister.NewLister() lister.OperatorsV1alpha1().RegisterSubscriptionLister(namespace, informerFactory.Operators().V1alpha1().Subscriptions().Lister()) lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(namespace, informerFactory.Operators().V1alpha1().ClusterServiceVersions().Lister()) - resolver := NewOperatorsV1alpha1Resolver(lister, clientFake) + resolver := NewOperatorsV1alpha1Resolver(lister, clientFake, kClientFake) querier := NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{catalog: tt.bundlesInCatalog}) - steps, subs, err := resolver.ResolveSteps(namespace, querier) + steps, _, subs, err := resolver.ResolveSteps(namespace, querier) require.Equal(t, tt.out.err, err) RequireStepsEqual(t, expectedSteps, steps) require.ElementsMatch(t, tt.out.subs, subs) diff --git a/pkg/controller/registry/resolver/steps.go b/pkg/controller/registry/resolver/steps.go index 3cec04f01f..7af58a3587 100644 --- a/pkg/controller/registry/resolver/steps.go +++ b/pkg/controller/registry/resolver/steps.go @@ -24,8 +24,12 @@ var ( ) func init() { - k8sscheme.AddToScheme(scheme) - extScheme.AddToScheme(scheme) + if err := k8sscheme.AddToScheme(scheme); err != nil { + panic(err) + } + if err := extScheme.AddToScheme(scheme); err != nil { + panic(err) + } if err := v1alpha1.AddToScheme(scheme); err != nil { panic(err) } diff --git a/pkg/fakes/fake_resolver.go b/pkg/fakes/fake_resolver.go index 52e00eca27..4aab97d482 100644 --- a/pkg/fakes/fake_resolver.go +++ b/pkg/fakes/fake_resolver.go @@ -9,7 +9,7 @@ import ( ) type FakeResolver struct { - ResolveStepsStub func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) + ResolveStepsStub func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) resolveStepsMutex sync.RWMutex resolveStepsArgsForCall []struct { arg1 string @@ -17,19 +17,21 @@ type FakeResolver struct { } resolveStepsReturns struct { result1 []*v1alpha1.Step - result2 []*v1alpha1.Subscription - result3 error + result2 []*v1alpha1.BundleLookup + result3 []*v1alpha1.Subscription + result4 error } resolveStepsReturnsOnCall map[int]struct { result1 []*v1alpha1.Step - result2 []*v1alpha1.Subscription - result3 error + result2 []*v1alpha1.BundleLookup + result3 []*v1alpha1.Subscription + result4 error } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } -func (fake *FakeResolver) ResolveSteps(arg1 string, arg2 resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error) { +func (fake *FakeResolver) ResolveSteps(arg1 string, arg2 resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error) { fake.resolveStepsMutex.Lock() ret, specificReturn := fake.resolveStepsReturnsOnCall[len(fake.resolveStepsArgsForCall)] fake.resolveStepsArgsForCall = append(fake.resolveStepsArgsForCall, struct { @@ -42,10 +44,10 @@ func (fake *FakeResolver) ResolveSteps(arg1 string, arg2 resolver.SourceQuerier) return fake.ResolveStepsStub(arg1, arg2) } if specificReturn { - return ret.result1, ret.result2, ret.result3 + return ret.result1, ret.result2, ret.result3, ret.result4 } fakeReturns := fake.resolveStepsReturns - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3, fakeReturns.result4 } func (fake *FakeResolver) ResolveStepsCallCount() int { @@ -54,7 +56,7 @@ func (fake *FakeResolver) ResolveStepsCallCount() int { return len(fake.resolveStepsArgsForCall) } -func (fake *FakeResolver) ResolveStepsCalls(stub func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.Subscription, error)) { +func (fake *FakeResolver) ResolveStepsCalls(stub func(string, resolver.SourceQuerier) ([]*v1alpha1.Step, []*v1alpha1.BundleLookup, []*v1alpha1.Subscription, error)) { fake.resolveStepsMutex.Lock() defer fake.resolveStepsMutex.Unlock() fake.ResolveStepsStub = stub @@ -67,33 +69,36 @@ func (fake *FakeResolver) ResolveStepsArgsForCall(i int) (string, resolver.Sourc return argsForCall.arg1, argsForCall.arg2 } -func (fake *FakeResolver) ResolveStepsReturns(result1 []*v1alpha1.Step, result2 []*v1alpha1.Subscription, result3 error) { +func (fake *FakeResolver) ResolveStepsReturns(result1 []*v1alpha1.Step, result2 []*v1alpha1.BundleLookup, result3 []*v1alpha1.Subscription, result4 error) { fake.resolveStepsMutex.Lock() defer fake.resolveStepsMutex.Unlock() fake.ResolveStepsStub = nil fake.resolveStepsReturns = struct { result1 []*v1alpha1.Step - result2 []*v1alpha1.Subscription - result3 error - }{result1, result2, result3} + result2 []*v1alpha1.BundleLookup + result3 []*v1alpha1.Subscription + result4 error + }{result1, result2, result3, result4} } -func (fake *FakeResolver) ResolveStepsReturnsOnCall(i int, result1 []*v1alpha1.Step, result2 []*v1alpha1.Subscription, result3 error) { +func (fake *FakeResolver) ResolveStepsReturnsOnCall(i int, result1 []*v1alpha1.Step, result2 []*v1alpha1.BundleLookup, result3 []*v1alpha1.Subscription, result4 error) { fake.resolveStepsMutex.Lock() defer fake.resolveStepsMutex.Unlock() fake.ResolveStepsStub = nil if fake.resolveStepsReturnsOnCall == nil { fake.resolveStepsReturnsOnCall = make(map[int]struct { result1 []*v1alpha1.Step - result2 []*v1alpha1.Subscription - result3 error + result2 []*v1alpha1.BundleLookup + result3 []*v1alpha1.Subscription + result4 error }) } fake.resolveStepsReturnsOnCall[i] = struct { result1 []*v1alpha1.Step - result2 []*v1alpha1.Subscription - result3 error - }{result1, result2, result3} + result2 []*v1alpha1.BundleLookup + result3 []*v1alpha1.Subscription + result4 error + }{result1, result2, result3, result4} } func (fake *FakeResolver) Invocations() map[string][][]interface{} { diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go index 9400bcf6eb..7bb2e85aec 100644 --- a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go +++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go @@ -3,11 +3,14 @@ package configmap import ( "errors" "fmt" - libbundle "github.com/operator-framework/operator-registry/pkg/lib/bundle" - "github.com/operator-framework/operator-registry/pkg/registry" + "strings" + "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - "strings" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" + "github.com/operator-framework/operator-registry/pkg/api" + "github.com/operator-framework/operator-registry/pkg/registry" ) func NewBundleLoader() *BundleLoader { @@ -21,12 +24,6 @@ func NewBundleLoaderWithLogger(logger *logrus.Entry) *BundleLoader { } } -// Manifest contains a bundle and a PackageManifest. -type Manifest struct { - Bundle *registry.Bundle - PackageManifest *registry.PackageManifest -} - type BundleLoader struct { logger *logrus.Entry } @@ -35,7 +32,7 @@ type BundleLoader struct { // creates an operator registry Bundle object. // If the Data section has a PackageManifest resource then it is also // deserialized and included in the result. -func (l *BundleLoader) Load(cm *corev1.ConfigMap) (manifest *Manifest, err error) { +func (l *BundleLoader) Load(cm *corev1.ConfigMap) (bundle *api.Bundle, err error) { if cm == nil { err = errors.New("ConfigMap must not be ") return @@ -45,48 +42,17 @@ func (l *BundleLoader) Load(cm *corev1.ConfigMap) (manifest *Manifest, err error "configmap": fmt.Sprintf("%s/%s", cm.GetNamespace(), cm.GetName()), }) - bundle, _, bundleErr := loadBundle(logger, cm.Data) + bundle, skipped, bundleErr := loadBundle(logger, cm.Data) if bundleErr != nil { err = fmt.Errorf("failed to extract bundle from configmap - %v", bundleErr) return } - - // get package manifest information from required annotations - annotations := cm.GetAnnotations() - if len(annotations) == 0 { - err = fmt.Errorf("missing required annoations on configmap %v", cm.GetName()) - return - } - - switch mediatype := annotations[libbundle.MediatypeLabel]; mediatype { - case "registry+v1": - // supported, proceed - default: - err = fmt.Errorf("failed to parse annotations due to unsupported media type %v", mediatype) - return - } - - var packageChannels []registry.PackageChannel - channels := strings.Split(annotations[libbundle.ChannelsLabel], ",") - for _, channel := range channels { - packageChannels = append(packageChannels, registry.PackageChannel{ - Name: channel, - }) - } - - manifest = &Manifest{ - Bundle: bundle, - PackageManifest: ®istry.PackageManifest{ - PackageName: annotations[libbundle.PackageLabel], - Channels: packageChannels, - DefaultChannelName: annotations[libbundle.ChannelDefaultLabel], - }, - } + l.logger.Debug("couldn't unpack skipped: %#v", skipped) return } -func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *registry.Bundle, skipped map[string]string, err error) { - bundle = ®istry.Bundle{} +func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *api.Bundle, skipped map[string]string, err error) { + bundle = &api.Bundle{Object: []string{}} skipped = map[string]string{} // Add kube resources to the bundle. @@ -106,44 +72,12 @@ func loadBundle(entry *logrus.Entry, data map[string]string) (bundle *registry.B continue } - // It's a valid kube resource, - // could be a crd, csv or other raw kube manifest(s). - bundle.Add(resource) + if resource.GetKind() == v1alpha1.ClusterServiceVersionKind { + bundle.CsvJson = content + } + bundle.Object = append(bundle.Object, content) logger.Infof("added to bundle, Kind=%s", resource.GetKind()) } return } - -func loadPackageManifest(entry *logrus.Entry, resources map[string]string) *registry.PackageManifest { - // Let's inspect if any of the skipped non kube resources is a PackageManifest type. - // The first one we run into will be selected. - for name, content := range resources { - logger := entry.WithFields(logrus.Fields{ - "key": name, - }) - - // Is it a package yaml file? - reader := strings.NewReader(content) - packageManifest, decodeErr := registry.DecodePackageManifest(reader) - if decodeErr != nil { - logger.Infof("skipping, not a PackageManifest type - %v", decodeErr) - continue - } - - logger.Infof("found a PackageManifest type resource - packageName=%s", packageManifest.PackageName) - - return packageManifest - } - - return nil -} - -func extract(data map[string]string) []string { - resources := make([]string, 0) - for _, v := range data { - resources = append(resources, v) - } - - return resources -} diff --git a/vendor/modules.txt b/vendor/modules.txt index ac4c013022..6c891edad8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -156,20 +156,13 @@ github.com/openshift/client-go/config/informers/externalversions/config github.com/openshift/client-go/config/informers/externalversions/config/v1 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces github.com/openshift/client-go/config/listers/config/v1 -<<<<<<< ours # github.com/operator-framework/operator-registry v1.5.3 -======= -# github.com/operator-framework/operator-registry v1.5.2-0.20191101035332-d2b7fe75b79c ->>>>>>> theirs github.com/operator-framework/operator-registry/pkg/api github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1 github.com/operator-framework/operator-registry/pkg/client -<<<<<<< ours -github.com/operator-framework/operator-registry/pkg/containertools -======= github.com/operator-framework/operator-registry/pkg/configmap +github.com/operator-framework/operator-registry/pkg/containertools github.com/operator-framework/operator-registry/pkg/lib/bundle ->>>>>>> theirs github.com/operator-framework/operator-registry/pkg/registry github.com/operator-framework/operator-registry/pkg/server github.com/operator-framework/operator-registry/pkg/sqlite