Skip to content

Commit 56a5794

Browse files
committed
Bug 1847540: resolve only default channels
Non deterministic behavior was introduced where, in some cases, the dependency resolver would select a channel entry from the registry that was not part of the default channel and create a subscription on that channel. This bugfix updates the registry client's filter function to ignore non default channel entries.
1 parent 21d67c1 commit 56a5794

File tree

1 file changed

+47
-13
lines changed

1 file changed

+47
-13
lines changed

pkg/controller/registry/registry_client.go

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,12 @@ func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, ki
8686
if err != nil {
8787
return nil, err
8888
}
89-
entry := rc.filterChannelEntries(it, excludedPkgName)
89+
entry, err := rc.filterChannelEntries(ctx, it, excludedPkgName)
90+
if err != nil {
91+
return nil, err
92+
}
9093
if entry == nil {
91-
return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s", excludedPkgName)
94+
return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s's default channel", excludedPkgName)
9295
}
9396
bundle, err := rc.Client.Registry.GetBundle(ctx, &registryapi.GetBundleRequest{PkgName: entry.PackageName, ChannelName: entry.ChannelName, CsvName: entry.BundleName})
9497
if err != nil {
@@ -97,25 +100,56 @@ func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, ki
97100
return bundle, nil
98101
}
99102

100-
// FilterChannelEntries filters out a channel entries that provide the requested
103+
// FilterChannelEntries filters out channel entries that provide the requested
101104
// 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 {
105+
// first entry on the list from the default channel of that package
106+
func (rc *Client) filterChannelEntries(ctx context.Context, it *ChannelEntryIterator, excludedPkgName string) (*opregistry.ChannelEntry, error) {
107+
defChannels := make(map[string]string, 0)
108+
104109
var entries []*opregistry.ChannelEntry
105110
for e := it.Next(); e != nil; e = it.Next() {
106111
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+
// keep track of the default channel for each package
113+
if _, ok := defChannels[e.PackageName]; !ok {
114+
defChannel, err := rc.getDefaultPackageChannel(ctx, e.PackageName)
115+
if err != nil {
116+
return nil, err
117+
}
118+
defChannels[e.PackageName] = defChannel
119+
}
120+
121+
// only add entry to the list if the entry is in the default channel
122+
if e.ChannelName == defChannels[e.PackageName] {
123+
entry := &opregistry.ChannelEntry{
124+
PackageName: e.PackageName,
125+
ChannelName: e.ChannelName,
126+
BundleName: e.BundleName,
127+
Replaces: e.Replaces,
128+
}
129+
entries = append(entries, entry)
112130
}
113-
entries = append(entries, entry)
114131
}
115132
}
116133

117134
if entries != nil {
118-
return entries[0]
135+
return entries[0], nil
136+
}
137+
return nil, nil
138+
}
139+
140+
// GetDefaultPackageChannel uses registry client to get the default
141+
// channel name for a given package name
142+
func (rc *Client) getDefaultPackageChannel(ctx context.Context, pkgName string) (string, error) {
143+
pkg, err := rc.Client.Registry.GetPackage(ctx, &registryapi.GetPackageRequest{Name: pkgName})
144+
if err != nil {
145+
return "", err
146+
}
147+
148+
var defChan string
149+
if pkg != nil {
150+
defChan = pkg.DefaultChannelName
151+
} else {
152+
return "", fmt.Errorf("package %s not found in registry", pkgName)
119153
}
120-
return nil
154+
return defChan, nil
121155
}

0 commit comments

Comments
 (0)