Skip to content

Commit abdd0f2

Browse files
committed
fix(index): account for default channel in index add order
Ensure the default channel referenced by a bundle exists, either by that bundle or in the package, before returning it as the next element of an input stream. Adding this check prevents smaller versions from breaking index add when the `--overwrite-latest` flag is set; e.g. if a z-stream bundle was originally added _after_ a larger y-stream and references a default channel only defined in that y-stream.
1 parent beace54 commit abdd0f2

File tree

3 files changed

+152
-7
lines changed

3 files changed

+152
-7
lines changed

pkg/registry/input_stream.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,23 @@ func (r *ReplacesInputStream) canAdd(bundle *Bundle, packageGraph *Package) erro
9393
return fmt.Errorf("Invalid bundle %s, replaces nonexistent bundle %s", bundle.Name, replaces)
9494
}
9595

96+
defaultChannel := bundle.Annotations.DefaultChannelName
97+
if defaultChannel != "" && !packageGraph.HasChannel(defaultChannel) {
98+
// We also can't add if the bundle isn't in the default channel it specifies or it doesn't already exist in the package
99+
var defaultFound bool
100+
for _, channel := range bundle.Channels {
101+
if channel != defaultChannel {
102+
continue
103+
}
104+
defaultFound = true
105+
break
106+
}
107+
108+
if !defaultFound {
109+
return fmt.Errorf("Invalid bundle %s, references nonexistent default channel %s", bundle.Name, defaultChannel)
110+
}
111+
}
112+
96113
images, ok := r.packages[packageGraph.Name]
97114
if !ok || images == nil {
98115
// This shouldn't happen unless canAdd is being called without the correct setup

pkg/registry/input_stream_test.go

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"math"
55
"math/rand"
66
"reflect"
7+
"strings"
78
"testing"
89
"testing/quick"
910

@@ -31,17 +32,25 @@ func unstructuredCSV() *unstructured.Unstructured {
3132
}
3233

3334
type inputConfig struct {
34-
pkg string
35-
name string
36-
version string
37-
replaces string
35+
pkg string
36+
name string
37+
version string
38+
replaces string
39+
defaultChannel string
40+
channels []string
3841
}
3942

4043
func newImageInput(config *inputConfig) *registry.ImageInput {
4144
image := &registry.ImageInput{
4245
Bundle: &registry.Bundle{
43-
Package: config.pkg,
44-
Name: config.name,
46+
Package: config.pkg,
47+
Name: config.name,
48+
Channels: config.channels,
49+
Annotations: &registry.Annotations{
50+
PackageName: config.pkg,
51+
Channels: strings.Join(config.channels, ","),
52+
DefaultChannelName: config.defaultChannel,
53+
},
4554
},
4655
}
4756

@@ -280,6 +289,125 @@ func TestReplacesTakesPrecedence(t *testing.T) {
280289
}
281290
}
282291

292+
func TestDefaultChannelAffectsOrder(t *testing.T) {
293+
type args struct {
294+
input []*registry.ImageInput
295+
}
296+
type expect struct {
297+
err bool
298+
ordered []string
299+
}
300+
for _, tt := range []struct {
301+
description string
302+
args args
303+
expect expect
304+
}{
305+
{
306+
description: "BundleDefiningDefaultChannelIsFirst",
307+
args: args{
308+
input: []*registry.ImageInput{
309+
newImageInput(&inputConfig{
310+
name: "a",
311+
version: "1.0.0",
312+
channels: []string{"stable"},
313+
defaultChannel: "alpha",
314+
}),
315+
newImageInput(&inputConfig{
316+
name: "b",
317+
version: "1.1.0",
318+
channels: []string{"alpha", "stable"},
319+
defaultChannel: "alpha",
320+
}),
321+
},
322+
},
323+
expect: expect{
324+
ordered: []string{"b", "a"},
325+
},
326+
},
327+
{
328+
description: "ConflictingReplacesAndDefaultChannelReturnsError",
329+
args: args{
330+
input: []*registry.ImageInput{
331+
newImageInput(&inputConfig{
332+
name: "a",
333+
version: "1.0.0",
334+
channels: []string{"stable"},
335+
defaultChannel: "alpha",
336+
}),
337+
newImageInput(&inputConfig{
338+
name: "b",
339+
version: "1.1.0",
340+
replaces: "a",
341+
channels: []string{"alpha", "stable"},
342+
defaultChannel: "alpha",
343+
}),
344+
},
345+
},
346+
expect: expect{
347+
err: true,
348+
},
349+
},
350+
} {
351+
t.Run(tt.description, func(t *testing.T) {
352+
addedChannels := map[string]registry.Channel{}
353+
loader := &registryfakes.FakeGraphLoader{
354+
GenerateStub: func(pkg string) (*registry.Package, error) {
355+
return &registry.Package{
356+
Name: pkg,
357+
Channels: addedChannels,
358+
}, nil
359+
},
360+
}
361+
362+
stream, err := registry.NewReplacesInputStream(loader, tt.args.input)
363+
if err != nil {
364+
t.Error(err)
365+
return
366+
}
367+
368+
if tt.expect.err {
369+
_, err := stream.Next()
370+
if err == nil {
371+
t.Error("expected next to return error, returned nil instead")
372+
}
373+
return
374+
}
375+
376+
for _, expected := range tt.expect.ordered {
377+
next, err := stream.Next()
378+
if err != nil {
379+
t.Errorf("next returned unexpected error %s", err)
380+
return
381+
}
382+
if next == nil {
383+
t.Errorf("next returned unexpected nil, expecting %s", expected)
384+
return
385+
}
386+
387+
name := next.Bundle.Name
388+
if name != expected {
389+
t.Errorf("next returned unexpected bundle %s, expecting %s", name, expected)
390+
return
391+
}
392+
393+
// Simulate an add
394+
for _, channel := range next.Bundle.Channels {
395+
added := addedChannels[channel]
396+
if added.Nodes == nil {
397+
added.Nodes = map[registry.BundleKey]map[registry.BundleKey]struct{}{}
398+
}
399+
added.Nodes[registry.BundleKey{CsvName: name}] = nil
400+
addedChannels[channel] = added
401+
}
402+
}
403+
404+
if !stream.Empty() {
405+
t.Errorf("stream still contains content, expected end of content")
406+
}
407+
})
408+
}
409+
}
410+
283411
type missingReplaces struct {
284412
input []*registry.ImageInput
285413
valid int

pkg/registry/populator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ func SemverPackageManifest(bundles []*Bundle) (*PackageManifest, error) {
487487
}
488488

489489
if !defaultFound {
490-
return nil, fmt.Errorf("unable to determine default channel")
490+
return nil, fmt.Errorf("unable to determine default channel among channel heads: %+v", heads)
491491
}
492492

493493
return pkg, nil

0 commit comments

Comments
 (0)