Skip to content

Commit e8e04d1

Browse files
joelanfordtimflannagan
authored andcommitted
pkg/sqlite: use consistent starting depth when building channel_entry table (#868)
* pkg/sqlite: use consistent starting depth when building channel_entry table When building the channel_entry table, always using a starting depth of 0. This is important because the ListBundles query makes an assumption that all packages in the database will have the same minimum depth. Signed-off-by: Joe Lanford <[email protected]> * pkg/sqlite/load.go: add descriptive comments for startDepth Signed-off-by: Joe Lanford <[email protected]> Upstream-repository: operator-registry Upstream-commit: f478fddfe36153536fdef0e1f30f673fd85a94d7
1 parent 10c3f2f commit e8e04d1

File tree

3 files changed

+114
-8
lines changed
  • staging/operator-registry/pkg/sqlite
  • vendor/github.com/operator-framework/operator-registry/pkg/sqlite

3 files changed

+114
-8
lines changed

staging/operator-registry/pkg/sqlite/load.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ type MigratableLoader interface {
2828

2929
var _ MigratableLoader = &sqlLoader{}
3030

31+
// startDepth is the depth that channel heads should be assigned
32+
// in the channel_entry table. This const exists so that all
33+
// add modes (replaces, semver, and semver-skippatch) are
34+
// consistent.
35+
const startDepth = 0
36+
3137
func newSQLLoader(db *sql.DB, opts ...DbOption) (*sqlLoader, error) {
3238
options := defaultDBOptions()
3339
for _, o := range opts {
@@ -424,7 +430,7 @@ func (s *sqlLoader) AddPackageChannelsFromGraph(graph *registry.Package) error {
424430
// update each channel's graph
425431
for channelName, channel := range graph.Channels {
426432
currentNode := channel.Head
427-
depth := 1
433+
depth := startDepth
428434

429435
var previousNodeID int64
430436

@@ -495,7 +501,12 @@ func (s *sqlLoader) AddPackageChannelsFromGraph(graph *registry.Package) error {
495501

496502
// we got to the end of the channel graph
497503
if nextNode.IsEmpty() {
498-
if len(channel.Nodes) != depth {
504+
// expectedDepth is:
505+
// <number-of-nodes> + <start-depth> - 1
506+
// For example, if the number of nodes is 3 and the startDepth is 0, the expected depth is 2 (0, 1, 2)
507+
// If the number of nodes is 5 and the startDepth is 3, the expected depth is 7 (3, 4, 5, 6, 7)
508+
expectedDepth := len(channel.Nodes) + startDepth - 1
509+
if expectedDepth != depth {
499510
err := fmt.Errorf("Invalid graph: some (non-bottom) nodes defined in the graph were not mentioned as replacements of any node")
500511
errs = append(errs, err)
501512
}
@@ -608,7 +619,7 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani
608619
}
609620

610621
for _, c := range channels {
611-
res, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, 0)
622+
res, err := addChannelEntry.Exec(c.Name, manifest.PackageName, c.CurrentCSVName, startDepth)
612623
if err != nil {
613624
errs = append(errs, fmt.Errorf("failed to add channel %q in package %q: %s", c.Name, manifest.PackageName, err.Error()))
614625
continue
@@ -620,7 +631,10 @@ func (s *sqlLoader) addPackageChannels(tx *sql.Tx, manifest registry.PackageMani
620631
}
621632

622633
channelEntryCSVName := c.CurrentCSVName
623-
depth := 1
634+
635+
// depth is set to `startDepth + 1` here because we already added the channel head
636+
// with depth `startDepth` above.
637+
depth := startDepth + 1
624638

625639
// Since this loop depends on following 'replaces', keep track of where it's been
626640
replaceCycle := map[string]bool{channelEntryCSVName: true}

staging/operator-registry/pkg/sqlite/load_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"encoding/json"
7+
"errors"
78
"fmt"
89
"strings"
910
"testing"
@@ -154,6 +155,71 @@ func TestAddPackageChannels(t *testing.T) {
154155
}
155156
}
156157

158+
func TestAddBundleSemver(t *testing.T) {
159+
// Create a test DB
160+
db, cleanup := CreateTestDb(t)
161+
defer cleanup()
162+
store, err := NewSQLLiteLoader(db)
163+
require.NoError(t, err)
164+
err = store.Migrate(context.TODO())
165+
require.NoError(t, err)
166+
graphLoader, err := NewSQLGraphLoaderFromDB(db)
167+
require.NoError(t, err)
168+
169+
// Seed the db with a replaces-mode bundle/package
170+
replacesBundle := newBundle(t, "csv-a", "pkg-foo", []string{"stable"}, newUnstructuredCSV(t, "csv-a", ""))
171+
err = store.AddOperatorBundle(replacesBundle)
172+
require.NoError(t, err)
173+
174+
err = store.AddPackageChannels(registry.PackageManifest{
175+
PackageName: "pkg-foo",
176+
Channels: []registry.PackageChannel{
177+
{
178+
Name: "stable",
179+
CurrentCSVName: "csv-a",
180+
},
181+
},
182+
DefaultChannelName: "stable",
183+
})
184+
require.NoError(t, err)
185+
186+
// Add semver bundles in non-semver order.
187+
bundles := []*registry.Bundle{
188+
newBundle(t, "csv-3", "pkg-0", []string{"stable"}, newUnstructuredCSVWithVersion(t, "csv-3", "0.3.0")),
189+
newBundle(t, "csv-1", "pkg-0", []string{"stable"}, newUnstructuredCSVWithVersion(t, "csv-1", "0.1.0")),
190+
newBundle(t, "csv-2", "pkg-0", []string{"stable"}, newUnstructuredCSVWithVersion(t, "csv-2", "0.2.0")),
191+
}
192+
for _, b := range bundles {
193+
graph, err := graphLoader.Generate(b.Package)
194+
require.Conditionf(t, func() bool {
195+
return err == nil || errors.Is(err, registry.ErrPackageNotInDatabase)
196+
}, "got unexpected error: %v", err)
197+
bundleLoader := registry.BundleGraphLoader{}
198+
updatedGraph, err := bundleLoader.AddBundleToGraph(b, graph, &registry.AnnotationsFile{Annotations: *b.Annotations}, false)
199+
require.NoError(t, err)
200+
err = store.AddBundleSemver(updatedGraph, b)
201+
require.NoError(t, err)
202+
}
203+
204+
// Ensure bundles can be queried with expected replaces and skips values.
205+
querier := NewSQLLiteQuerierFromDb(db)
206+
gotBundles, err := querier.ListBundles(context.Background())
207+
require.NoError(t, err)
208+
replaces := map[string]string{}
209+
for _, b := range gotBundles {
210+
if b.PackageName != "pkg-0" {
211+
continue
212+
}
213+
require.Len(t, b.Skips, 0, "unexpected skips value(s) for bundle %q", b.CsvName)
214+
replaces[b.CsvName] = b.Replaces
215+
}
216+
require.Equal(t, map[string]string{
217+
"csv-3": "csv-2",
218+
"csv-2": "csv-1",
219+
"csv-1": "",
220+
}, replaces)
221+
}
222+
157223
func TestClearNonHeadBundles(t *testing.T) {
158224
db, cleanup := CreateTestDb(t)
159225
defer cleanup()
@@ -237,6 +303,18 @@ func newUnstructuredCSVWithSkips(t *testing.T, name, replaces string, skips ...s
237303
return &unstructured.Unstructured{Object: out}
238304
}
239305

306+
func newUnstructuredCSVWithVersion(t *testing.T, name, version string) *unstructured.Unstructured {
307+
csv := &registry.ClusterServiceVersion{}
308+
csv.TypeMeta.Kind = "ClusterServiceVersion"
309+
csv.SetName(name)
310+
versionJson := fmt.Sprintf(`{"version": "%s"}`, version)
311+
csv.Spec = json.RawMessage(versionJson)
312+
313+
out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(csv)
314+
require.NoError(t, err)
315+
return &unstructured.Unstructured{Object: out}
316+
}
317+
240318
func newBundle(t *testing.T, name, pkgName string, channels []string, objs ...*unstructured.Unstructured) *registry.Bundle {
241319
bundle := registry.NewBundle(name, &registry.Annotations{
242320
PackageName: pkgName,

vendor/github.com/operator-framework/operator-registry/pkg/sqlite/load.go

Lines changed: 18 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)