Skip to content

Commit f634a5a

Browse files
Merge pull request #448 from gallettilance/force-bundle
Bug 1880501: Adding overwrite-latest flag to index add
2 parents 0e50c92 + 16b91b8 commit f634a5a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+13285
-116
lines changed

cmd/opm/index/add.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ func addIndexAddCmd(parent *cobra.Command) {
6262
indexCmd.Flags().Bool("permissive", false, "allow registry load errors")
6363
indexCmd.Flags().StringP("mode", "", "replaces", "graph update mode that defines how channel graphs are updated. One of: [replaces, semver, semver-skippatch]")
6464

65+
indexCmd.Flags().Bool("overwrite-latest", false, "overwrite the latest bundles (channel heads) with those of the same csv name given by --bundles")
66+
if err := indexCmd.Flags().MarkHidden("overwrite-latest"); err != nil {
67+
logrus.Panic(err.Error())
68+
}
6569
if err := indexCmd.Flags().MarkHidden("debug"); err != nil {
6670
logrus.Panic(err.Error())
6771
}
@@ -118,6 +122,11 @@ func runIndexAddCmdFunc(cmd *cobra.Command, args []string) error {
118122
return err
119123
}
120124

125+
overwrite, err := cmd.Flags().GetBool("overwrite-latest")
126+
if err != nil {
127+
return err
128+
}
129+
121130
modeEnum, err := registry.GetModeFromString(mode)
122131
if err != nil {
123132
return err
@@ -147,6 +156,7 @@ func runIndexAddCmdFunc(cmd *cobra.Command, args []string) error {
147156
Permissive: permissive,
148157
Mode: modeEnum,
149158
SkipTLS: skipTLS,
159+
Overwrite: overwrite,
150160
}
151161

152162
err = indexAdder.AddToIndex(request)

cmd/opm/registry/add.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ func addFunc(cmd *cobra.Command, args []string) error {
7373
Bundles: bundleImages,
7474
Mode: modeEnum,
7575
ContainerTool: containertools.NewContainerTool(containerTool, containertools.NoneTool),
76+
Overwrite: false,
7677
}
7778

7879
logger := logrus.WithFields(logrus.Fields{"bundles": bundleImages})

pkg/lib/indexer/indexer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type AddToIndexRequest struct {
6565
Mode pregistry.Mode
6666
CaFile string
6767
SkipTLS bool
68+
Overwrite bool
6869
}
6970

7071
// AddToIndex is an aggregate API used to generate a registry index image with additional bundles
@@ -88,6 +89,7 @@ func (i ImageIndexer) AddToIndex(request AddToIndexRequest) error {
8889
Mode: request.Mode,
8990
SkipTLS: request.SkipTLS,
9091
ContainerTool: i.PullTool,
92+
Overwrite: request.Overwrite,
9193
}
9294

9395
// Add the bundles to the registry

pkg/lib/registry/registry.go

Lines changed: 89 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ type AddToRegistryRequest struct {
3131
Bundles []string
3232
Mode registry.Mode
3333
ContainerTool containertools.ContainerTool
34+
Overwrite bool
3435
}
3536

3637
func (r RegistryUpdater) AddToRegistry(request AddToRegistryRequest) error {
37-
db, err := sql.Open("sqlite3", request.InputDatabase)
38+
db, err := sql.Open("sqlite3", "file:"+request.InputDatabase+"?_foreign_keys=on")
3839
if err != nil {
3940
return err
4041
}
@@ -84,51 +85,115 @@ func (r RegistryUpdater) AddToRegistry(request AddToRegistryRequest) error {
8485
simpleRefs = append(simpleRefs, image.SimpleReference(ref))
8586
}
8687

87-
if err := populate(context.TODO(), dbLoader, graphLoader, dbQuerier, reg, simpleRefs, request.Mode); err != nil {
88+
if err := populate(context.TODO(), dbLoader, graphLoader, dbQuerier, reg, simpleRefs, request.Mode, request.Overwrite); err != nil {
8889
r.Logger.Debugf("unable to populate database: %s", err)
8990

9091
if !request.Permissive {
9192
r.Logger.WithError(err).Error("permissive mode disabled")
9293
return err
93-
} else {
94-
r.Logger.WithError(err).Warn("permissive mode enabled")
9594
}
95+
r.Logger.WithError(err).Warn("permissive mode enabled")
9696
}
9797

9898
return nil
9999
}
100100

101-
func populate(ctx context.Context, loader registry.Load, graphLoader registry.GraphLoader, querier registry.Query, reg image.Registry, refs []image.Reference, mode registry.Mode) error {
101+
func unpackImage(ctx context.Context, reg image.Registry, ref image.Reference) (image.Reference, string, func(), error) {
102102
var errs []error
103+
workingDir, err := ioutil.TempDir("./", "bundle_tmp")
104+
if err != nil {
105+
errs = append(errs, err)
106+
}
103107

104-
unpackedImageMap := make(map[image.Reference]string, 0)
105-
for _, ref := range refs {
106-
workingDir, err := ioutil.TempDir("./", "bundle_tmp")
107-
if err != nil {
108-
errs = append(errs, err)
109-
continue
110-
}
111-
defer os.RemoveAll(workingDir)
108+
if err = reg.Pull(ctx, ref); err != nil {
109+
errs = append(errs, err)
110+
}
112111

113-
if err = reg.Pull(ctx, ref); err != nil {
114-
errs = append(errs, err)
115-
continue
116-
}
112+
if err = reg.Unpack(ctx, ref, workingDir); err != nil {
113+
errs = append(errs, err)
114+
}
117115

118-
if err = reg.Unpack(ctx, ref, workingDir); err != nil {
119-
errs = append(errs, err)
120-
continue
116+
cleanup := func() {
117+
if err := os.RemoveAll(workingDir); err != nil {
118+
logrus.Error(err)
121119
}
122-
123-
unpackedImageMap[ref] = workingDir
124120
}
125121

126122
if len(errs) > 0 {
127-
return utilerrors.NewAggregate(errs)
123+
return nil, "", cleanup, utilerrors.NewAggregate(errs)
124+
}
125+
return ref, workingDir, cleanup, nil
126+
}
127+
128+
func populate(ctx context.Context, loader registry.Load, graphLoader registry.GraphLoader, querier registry.Query, reg image.Registry, refs []image.Reference, mode registry.Mode, overwrite bool) error {
129+
unpackedImageMap := make(map[image.Reference]string, 0)
130+
for _, ref := range refs {
131+
to, from, cleanup, err := unpackImage(ctx, reg, ref)
132+
if err != nil {
133+
return err
134+
}
135+
unpackedImageMap[to] = from
136+
defer cleanup()
128137
}
129138

130-
populator := registry.NewDirectoryPopulator(loader, graphLoader, querier, unpackedImageMap)
139+
overwriteImageMap := make(map[string]map[image.Reference]string, 0)
140+
if overwrite {
141+
// find all bundles that are attempting to overwrite
142+
for to, from := range unpackedImageMap {
143+
img, err := registry.NewImageInput(to, from)
144+
if err != nil {
145+
return err
146+
}
147+
overwritten, err := querier.GetBundlePathIfExists(ctx, img.Bundle.Name)
148+
if err != nil {
149+
if err == registry.ErrBundleImageNotInDatabase {
150+
continue
151+
}
152+
return err
153+
}
154+
if overwritten != "" {
155+
// get all bundle paths for that package - we will re-add these to regenerate the graph
156+
bundles, err := querier.GetBundlesForPackage(ctx, img.Bundle.Package)
157+
if err != nil {
158+
return err
159+
}
160+
cleanups := make(chan func(), 1)
161+
errs := make(chan error, 1)
162+
for bundle := range bundles {
163+
if _, ok := overwriteImageMap[img.Bundle.Package]; !ok {
164+
overwriteImageMap[img.Bundle.Package] = make(map[image.Reference]string, 0)
165+
}
166+
// parallelize image pulls
167+
go func(bundle registry.BundleKey, img *registry.ImageInput) {
168+
if bundle.CsvName != img.Bundle.Name {
169+
to, from, cleanup, err := unpackImage(ctx, reg, image.SimpleReference(bundle.BundlePath))
170+
if err != nil {
171+
errs <- err
172+
}
173+
cleanups <- cleanup
174+
overwriteImageMap[img.Bundle.Package][to] = from
175+
} else {
176+
overwriteImageMap[img.Bundle.Package][to] = from
177+
delete(unpackedImageMap, to)
178+
}
179+
}(bundle, img)
180+
}
181+
for i := 0; i < len(bundles)-1; i++ {
182+
select {
183+
case err := <-errs:
184+
return err
185+
default:
186+
cleanup := <-cleanups
187+
defer cleanup()
188+
}
189+
}
190+
} else {
191+
return fmt.Errorf("index add --overwrite-latest is only supported when using bundle images")
192+
}
193+
}
194+
}
131195

196+
populator := registry.NewDirectoryPopulator(loader, graphLoader, querier, unpackedImageMap, overwriteImageMap, overwrite)
132197
return populator.Populate(mode)
133198
}
134199

pkg/registry/bundle.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ func NewBundleFromStrings(name, pkgName string, channels []string, objs []string
7373
func (b *Bundle) Size() int {
7474
return len(b.Objects)
7575
}
76-
7776
func (b *Bundle) Add(obj *unstructured.Unstructured) {
7877
b.Objects = append(b.Objects, obj)
7978
b.cacheStale = true

pkg/registry/empty.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ func (EmptyQuery) GetDependenciesForBundle(ctx context.Context, name, version, p
104104
return nil, errors.New("empty querier: cannot get dependencies for bundle")
105105
}
106106

107+
func (EmptyQuery) GetBundlePathIfExists(ctx context.Context, csvName string) (bundlePath string, err error) {
108+
return "", errors.New("empty querier: cannot get bundle path for bundle")
109+
}
110+
107111
var _ Query = &EmptyQuery{}
108112

109113
func NewEmptyQuerier() *EmptyQuery {

pkg/registry/imageinput.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ type ImageInput struct {
1616
metadataDir string
1717
to image.Reference
1818
from string
19-
annotationsFile *AnnotationsFile
19+
AnnotationsFile *AnnotationsFile
2020
dependenciesFile *DependenciesFile
21-
bundle *Bundle
21+
Bundle *Bundle
2222
}
2323

2424
func NewImageInput(to image.Reference, from string) (*ImageInput, error) {
@@ -72,7 +72,7 @@ func NewImageInput(to image.Reference, from string) (*ImageInput, error) {
7272
metadataDir: metadata,
7373
to: to,
7474
from: from,
75-
annotationsFile: annotationsFile,
75+
AnnotationsFile: annotationsFile,
7676
dependenciesFile: dependenciesFile,
7777
}
7878

@@ -115,14 +115,14 @@ func (i *ImageInput) getBundleFromManifests() error {
115115
bundle.Dependencies = i.dependenciesFile.GetDependencies()
116116

117117
bundle.Name = csvName
118-
bundle.Package = i.annotationsFile.Annotations.PackageName
119-
bundle.Channels = strings.Split(i.annotationsFile.Annotations.Channels, ",")
118+
bundle.Package = i.AnnotationsFile.Annotations.PackageName
119+
bundle.Channels = strings.Split(i.AnnotationsFile.Annotations.Channels, ",")
120120

121121
if err := bundle.AllProvidedAPIsInBundle(); err != nil {
122122
return fmt.Errorf("error checking provided apis in bundle %s: %s", bundle.Name, err)
123123
}
124124

125-
i.bundle = bundle
125+
i.Bundle = bundle
126126

127127
return nil
128128
}

pkg/registry/interface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ type Query interface {
5757
ListBundles(ctx context.Context) (bundles []*api.Bundle, err error)
5858
// Get the list of dependencies for a bundle
5959
GetDependenciesForBundle(ctx context.Context, name, version, path string) (dependencies []*api.Dependency, err error)
60+
// Get the bundle path if it exists
61+
GetBundlePathIfExists(ctx context.Context, csvName string) (string, error)
6062
}
6163

6264
// GraphLoader generates a graph

0 commit comments

Comments
 (0)