Skip to content

Commit 53643ae

Browse files
Merge pull request #1571 from dinhxuanvu/ocs-fix-4.3
[release-4.3] Bug 1843694: fix(resolver): don't pick operator from same package when resolve requiredAPI
2 parents 65cc339 + df2f290 commit 53643ae

File tree

12 files changed

+2192
-327
lines changed

12 files changed

+2192
-327
lines changed

pkg/controller/registry/grpc/source.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"google.golang.org/grpc"
1010
"google.golang.org/grpc/connectivity"
1111

12+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
1213
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
13-
"github.com/operator-framework/operator-registry/pkg/client"
1414

1515
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1616
)
@@ -190,8 +190,8 @@ func (s *SourceStore) Remove(key resolver.CatalogKey) error {
190190
return source.Conn.Close()
191191
}
192192

193-
func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[resolver.CatalogKey]client.Interface {
194-
refs := map[resolver.CatalogKey]client.Interface{}
193+
func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[resolver.CatalogKey]registry.ClientInterface {
194+
refs := map[resolver.CatalogKey]registry.ClientInterface{}
195195
s.sourcesLock.RLock()
196196
defer s.sourcesLock.RUnlock()
197197
for key, source := range s.sources {
@@ -201,7 +201,7 @@ func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[reso
201201
if source.LastConnect.IsZero() {
202202
continue
203203
}
204-
refs[key] = client.NewClientFromConn(source.Conn)
204+
refs[key] = registry.NewClientFromConn(source.Conn)
205205
}
206206

207207
// TODO : remove unhealthy
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o resolver/fakes/fake_registry_client_interface.go . ClientInterface
2+
package registry
3+
4+
import (
5+
"context"
6+
"fmt"
7+
"io"
8+
9+
"google.golang.org/grpc"
10+
11+
registryapi "github.com/operator-framework/operator-registry/pkg/api"
12+
"github.com/operator-framework/operator-registry/pkg/client"
13+
opregistry "github.com/operator-framework/operator-registry/pkg/registry"
14+
)
15+
16+
// ChannelEntryStream interface
17+
type ChannelEntryStream interface {
18+
Recv() (*registryapi.ChannelEntry, error)
19+
}
20+
21+
// ClientInterface that extends client.Interface
22+
type ClientInterface interface {
23+
client.Interface
24+
FindBundleThatProvides(ctx context.Context, group, version, kind, excludedPkgName string) (*registryapi.Bundle, error)
25+
GetLatestChannelEntriesThatProvide(ctx context.Context, group, version, kind string) (*ChannelEntryIterator, error)
26+
}
27+
28+
// ChannelEntryIterator struct
29+
type ChannelEntryIterator struct {
30+
stream ChannelEntryStream
31+
error error
32+
}
33+
34+
// NewChannelEntryIterator returns a new ChannelEntryIterator
35+
func NewChannelEntryIterator(stream ChannelEntryStream) *ChannelEntryIterator {
36+
return &ChannelEntryIterator{stream: stream}
37+
}
38+
39+
// Next returns the next Channel Entry in the grpc stream
40+
func (ceit *ChannelEntryIterator) Next() *registryapi.ChannelEntry {
41+
if ceit.error != nil {
42+
return nil
43+
}
44+
next, err := ceit.stream.Recv()
45+
if err == io.EOF {
46+
return nil
47+
}
48+
if err != nil {
49+
ceit.error = err
50+
}
51+
return next
52+
}
53+
54+
func (ceit *ChannelEntryIterator) Error() error {
55+
return ceit.error
56+
}
57+
58+
// Client struct with a registry client embedded
59+
type Client struct {
60+
*client.Client
61+
}
62+
63+
// NewClientFromConn returns the next Channel Entry in the grpc stream
64+
func NewClientFromConn(conn *grpc.ClientConn) *Client {
65+
return &Client{
66+
Client: client.NewClientFromConn(conn),
67+
}
68+
}
69+
70+
var _ ClientInterface = &Client{}
71+
72+
// GetLatestChannelEntriesThatProvide uses registry client to get a list of
73+
// latest channel entries that provide the requested API (via an iterator)
74+
func (rc *Client) GetLatestChannelEntriesThatProvide(ctx context.Context, group, version, kind string) (*ChannelEntryIterator, error) {
75+
stream, err := rc.Client.Registry.GetLatestChannelEntriesThatProvide(ctx, &registryapi.GetLatestProvidersRequest{Group: group, Version: version, Kind: kind})
76+
if err != nil {
77+
return nil, err
78+
}
79+
return NewChannelEntryIterator(stream), nil
80+
}
81+
82+
// FindBundleThatProvides returns a bundle that provides the request API and
83+
// doesn't belong to the provided package
84+
func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, kind, excludedPkgName string) (*registryapi.Bundle, error) {
85+
it, err := rc.GetLatestChannelEntriesThatProvide(ctx, group, version, kind)
86+
if err != nil {
87+
return nil, err
88+
}
89+
entry := rc.filterChannelEntries(it, excludedPkgName)
90+
if entry == nil {
91+
return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s", excludedPkgName)
92+
}
93+
bundle, err := rc.Client.Registry.GetBundle(ctx, &registryapi.GetBundleRequest{PkgName: entry.PackageName, ChannelName: entry.ChannelName, CsvName: entry.BundleName})
94+
if err != nil {
95+
return nil, err
96+
}
97+
return bundle, nil
98+
}
99+
100+
// FilterChannelEntries filters out a channel entries that provide the requested
101+
// API and come from the same package with original operator and returns the
102+
// first entry on the list
103+
func (rc *Client) filterChannelEntries(it *ChannelEntryIterator, excludedPkgName string) *opregistry.ChannelEntry {
104+
var entries []*opregistry.ChannelEntry
105+
for e := it.Next(); e != nil; e = it.Next() {
106+
if e.PackageName != excludedPkgName {
107+
entry := &opregistry.ChannelEntry{
108+
PackageName: e.PackageName,
109+
ChannelName: e.ChannelName,
110+
BundleName: e.BundleName,
111+
Replaces: e.Replaces,
112+
}
113+
entries = append(entries, entry)
114+
}
115+
}
116+
117+
if entries != nil {
118+
return entries[0]
119+
}
120+
return nil
121+
}

pkg/controller/registry/resolver/evolver.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,14 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error {
130130
e.gen.MarkAPIChecked(*api)
131131

132132
// identify the initialSource
133-
initialSource := CatalogKey{}
133+
var initialSource *OperatorSourceInfo
134134
for _, operator := range e.gen.MissingAPIs()[*api] {
135-
initialSource = operator.SourceInfo().Catalog
135+
initialSource = operator.SourceInfo()
136136
break
137137
}
138138

139139
// attempt to find a bundle that provides that api
140-
if bundle, key, err := e.querier.FindProvider(*api, initialSource); err == nil {
140+
if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog, initialSource.Package); err == nil {
141141
// add a bundle that provides the api to the generation
142142
o, err := NewOperatorFromBundle(bundle, "", "", *key)
143143
if err != nil {

0 commit comments

Comments
 (0)