Skip to content

Commit a413d20

Browse files
committed
render: support rendering DC from packagemanifest and bundle directories
Signed-off-by: Joe Lanford <[email protected]>
1 parent a4fd56c commit a413d20

File tree

7 files changed

+342
-20
lines changed

7 files changed

+342
-20
lines changed

internal/action/render.go

+121-15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/h2non/filetype"
1515
"github.com/h2non/filetype/matchers"
16+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1617
"github.com/sirupsen/logrus"
1718
"k8s.io/apimachinery/pkg/util/sets"
1819

@@ -30,10 +31,12 @@ type RefType uint
3031

3132
const (
3233
RefBundleImage RefType = 1 << iota
34+
RefBundleDir
3335
RefSqliteImage
3436
RefSqliteFile
3537
RefDCImage
3638
RefDCDir
39+
RefPackageManifestDir
3740

3841
RefAll = 0
3942
)
@@ -100,25 +103,48 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) {
100103
}
101104

102105
func (r Render) renderReference(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) {
103-
if stat, serr := os.Stat(ref); serr == nil {
104-
if stat.IsDir() {
105-
if !r.AllowedRefMask.Allowed(RefDCDir) {
106-
return nil, fmt.Errorf("cannot render declarative config directory: %w", ErrNotAllowed)
106+
stat, err := os.Stat(ref)
107+
if err != nil {
108+
return r.imageToDeclcfg(ctx, ref)
109+
}
110+
if stat.IsDir() {
111+
dirEntries, err := os.ReadDir(ref)
112+
if err != nil {
113+
return nil, err
114+
}
115+
if isBundle(dirEntries) {
116+
// Looks like a bundle directory
117+
if !r.AllowedRefMask.Allowed(RefBundleDir) {
118+
return nil, fmt.Errorf("cannot render bundle directory: %w", ErrNotAllowed)
107119
}
108-
return declcfg.LoadFS(os.DirFS(ref))
109-
} else {
110-
// The only supported file type is an sqlite DB file,
111-
// since declarative configs will be in a directory.
112-
if err := checkDBFile(ref); err != nil {
120+
img, err := registry.NewImageInput(image.SimpleReference(""), ref)
121+
if err != nil {
113122
return nil, err
114123
}
115-
if !r.AllowedRefMask.Allowed(RefSqliteFile) {
116-
return nil, fmt.Errorf("cannot render sqlite file: %w", ErrNotAllowed)
124+
return bundleToDeclcfg(img.Bundle, true)
125+
} else if isPackageManifest(dirEntries) {
126+
// Looks like a package manifest directory
127+
if !r.AllowedRefMask.Allowed(RefPackageManifestDir) {
128+
return nil, fmt.Errorf("cannot render package manifest directory: %w", ErrNotAllowed)
117129
}
118-
return sqliteToDeclcfg(ctx, ref)
130+
return renderPackageManifest(ctx, ref)
119131
}
132+
133+
// Otherwise, assume it is a declarative config root directory.
134+
if !r.AllowedRefMask.Allowed(RefDCDir) {
135+
return nil, fmt.Errorf("cannot render declarative config directory: %w", ErrNotAllowed)
136+
}
137+
return declcfg.LoadFS(os.DirFS(ref))
138+
}
139+
// The only supported file type is an sqlite DB file,
140+
// since declarative configs will be in a directory.
141+
if err := checkDBFile(ref); err != nil {
142+
return nil, err
143+
}
144+
if !r.AllowedRefMask.Allowed(RefSqliteFile) {
145+
return nil, fmt.Errorf("cannot render sqlite file: %w", ErrNotAllowed)
120146
}
121-
return r.imageToDeclcfg(ctx, ref)
147+
return sqliteToDeclcfg(ctx, ref)
122148
}
123149

124150
func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.DeclarativeConfig, error) {
@@ -165,7 +191,7 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D
165191
return nil, err
166192
}
167193

168-
cfg, err = bundleToDeclcfg(img.Bundle)
194+
cfg, err = bundleToDeclcfg(img.Bundle, false)
169195
if err != nil {
170196
return nil, err
171197
}
@@ -273,7 +299,7 @@ func populateDBRelatedImages(ctx context.Context, cfg *declcfg.DeclarativeConfig
273299
return nil
274300
}
275301

276-
func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error) {
302+
func bundleToDeclcfg(bundle *registry.Bundle, inlineManifests bool) (*declcfg.DeclarativeConfig, error) {
277303
bundleProperties, err := registry.PropertiesFromBundle(bundle)
278304
if err != nil {
279305
return nil, fmt.Errorf("get properties for bundle %q: %v", bundle.Name, err)
@@ -283,13 +309,33 @@ func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error
283309
return nil, fmt.Errorf("get related images for bundle %q: %v", bundle.Name, err)
284310
}
285311

312+
var (
313+
objs []string
314+
csvJSON string
315+
)
316+
if inlineManifests {
317+
for _, obj := range bundle.Objects {
318+
objJSON, err := json.Marshal(obj)
319+
if err != nil {
320+
return nil, fmt.Errorf("marshal bundle object %q (kind: %q)", obj.GetName(), obj.GetKind())
321+
}
322+
bundleProperties = append(bundleProperties, property.MustBuildBundleObjectData(objJSON))
323+
objs = append(objs, string(objJSON))
324+
if obj.GetKind() == v1alpha1.ClusterServiceVersionKind && csvJSON == "" {
325+
csvJSON = string(objJSON)
326+
}
327+
}
328+
}
329+
286330
dBundle := declcfg.Bundle{
287331
Schema: "olm.bundle",
288332
Name: bundle.Name,
289333
Package: bundle.Package,
290334
Image: bundle.BundleImage,
291335
Properties: bundleProperties,
292336
RelatedImages: relatedImages,
337+
Objects: objs,
338+
CsvJSON: csvJSON,
293339
}
294340

295341
return &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{dBundle}}, nil
@@ -343,3 +389,63 @@ func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig
343389
}
344390
return out
345391
}
392+
393+
func isBundle(entries []os.DirEntry) bool {
394+
foundManifests := false
395+
foundMetadata := false
396+
for _, e := range entries {
397+
if e.IsDir() {
398+
switch e.Name() {
399+
case "manifests":
400+
foundManifests = true
401+
case "metadata":
402+
foundMetadata = true
403+
}
404+
}
405+
if foundMetadata && foundManifests {
406+
return true
407+
}
408+
}
409+
return false
410+
}
411+
412+
func isPackageManifest(entries []os.DirEntry) bool {
413+
for _, e := range entries {
414+
if strings.HasSuffix(e.Name(), ".package.yaml") || strings.HasSuffix(e.Name(), ".package.yml") {
415+
return true
416+
}
417+
}
418+
return false
419+
}
420+
421+
func renderPackageManifest(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) {
422+
tmpDB, err := os.CreateTemp("", "opm-render-pm-")
423+
if err != nil {
424+
return nil, err
425+
}
426+
if err := tmpDB.Close(); err != nil {
427+
return nil, err
428+
}
429+
430+
db, err := sqlite.Open(tmpDB.Name())
431+
if err != nil {
432+
return nil, err
433+
}
434+
defer db.Close()
435+
defer os.RemoveAll(tmpDB.Name())
436+
437+
dbLoader, err := sqlite.NewSQLLiteLoader(db)
438+
if err != nil {
439+
return nil, err
440+
}
441+
if err := dbLoader.Migrate(context.TODO()); err != nil {
442+
return nil, err
443+
}
444+
445+
loader := sqlite.NewSQLLoaderForDirectory(dbLoader, ref)
446+
if err := loader.Populate(); err != nil {
447+
return nil, fmt.Errorf("error loading manifests from directory: %s", err)
448+
}
449+
450+
return sqliteToDeclcfg(ctx, tmpDB.Name())
451+
}

0 commit comments

Comments
 (0)