Skip to content

Commit d85ba8b

Browse files
Refactor FBC-related functions and structs into a utility module
Signed-off-by: Venkat Ramaraju <[email protected]> Signed-off-by: rashmigottipati <[email protected]>
1 parent ceef70d commit d85ba8b

File tree

4 files changed

+183
-155
lines changed

4 files changed

+183
-155
lines changed

internal/olm/fbcutil/util.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright 2022 The Operator-SDK Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package fbcutil
16+
17+
import (
18+
"bytes"
19+
"context"
20+
"errors"
21+
"fmt"
22+
"io/ioutil"
23+
"os"
24+
25+
"github.com/operator-framework/operator-registry/alpha/action"
26+
"github.com/operator-framework/operator-registry/alpha/declcfg"
27+
declarativeconfig "github.com/operator-framework/operator-registry/alpha/declcfg"
28+
"github.com/operator-framework/operator-registry/pkg/containertools"
29+
registryutil "github.com/operator-framework/operator-sdk/internal/registry"
30+
log "github.com/sirupsen/logrus"
31+
)
32+
33+
const (
34+
SchemaChannel = "olm.channel"
35+
SchemaPackage = "olm.package"
36+
DefaultChannel = "operator-sdk-run"
37+
)
38+
39+
const (
40+
// defaultIndexImageBase is the base for defaultIndexImage. It is necessary to separate
41+
// them for string comparison when defaulting bundle add mode.
42+
DefaultIndexImageBase = "quay.io/operator-framework/opm:"
43+
// DefaultIndexImage is the index base image used if none is specified. It contains no bundles.
44+
// TODO(v2.0.0): pin this image tag to a specific version.
45+
DefaultIndexImage = DefaultIndexImageBase + "latest"
46+
)
47+
48+
// BundleDeclcfg represents a minimal File-Based Catalog.
49+
// This struct only consists of one Package, Bundle, and Channel blob. It is used to
50+
// represent the bundle image in the File-Based Catalog format.
51+
type BundleDeclcfg struct {
52+
Package declcfg.Package
53+
Channel declcfg.Channel
54+
Bundle declcfg.Bundle
55+
}
56+
57+
// FBCContext is a struct that stores all the required information while constructing
58+
// a new File-Based Catalog on the fly. The fields from this struct are passed as
59+
// parameters to Operator Registry API calls to generate declarative config objects.
60+
type FBCContext struct {
61+
Package string
62+
ChannelName string
63+
Refs []string
64+
ChannelEntry declarativeconfig.ChannelEntry
65+
}
66+
67+
// CreateFBC generates an FBC by creating bundle, package and channel blobs.
68+
func (f *FBCContext) CreateFBC(ctx context.Context) (BundleDeclcfg, error) {
69+
var bundleDC BundleDeclcfg
70+
// Rendering the bundle image into a declarative config format.
71+
declcfg, err := RenderRefs(ctx, f.Refs)
72+
if err != nil {
73+
return BundleDeclcfg{}, err
74+
}
75+
76+
// Ensuring a valid bundle size.
77+
if len(declcfg.Bundles) != 1 {
78+
return BundleDeclcfg{}, fmt.Errorf("bundle image should contain exactly one bundle blob")
79+
}
80+
81+
bundleDC.Bundle = declcfg.Bundles[0]
82+
83+
// generate package.
84+
bundleDC.Package = declarativeconfig.Package{
85+
Schema: SchemaPackage,
86+
Name: f.Package,
87+
DefaultChannel: f.ChannelName,
88+
}
89+
90+
// generate channel.
91+
bundleDC.Channel = declarativeconfig.Channel{
92+
Schema: SchemaChannel,
93+
Name: f.ChannelName,
94+
Package: f.Package,
95+
Entries: []declarativeconfig.ChannelEntry{f.ChannelEntry},
96+
}
97+
98+
return bundleDC, nil
99+
}
100+
101+
// ValidateAndStringify first converts the generated declarative config to a model and validates it.
102+
// If the declarative config model is valid, it will convert the declarative config to a YAML string and return it.
103+
func ValidateAndStringify(declcfg *declarativeconfig.DeclarativeConfig) (string, error) {
104+
// validates and converts declarative config to model
105+
_, err := declarativeconfig.ConvertToModel(*declcfg)
106+
if err != nil {
107+
return "", fmt.Errorf("error converting the declarative config to model: %v", err)
108+
}
109+
110+
var buf bytes.Buffer
111+
err = declarativeconfig.WriteYAML(*declcfg, &buf)
112+
if err != nil {
113+
return "", fmt.Errorf("error writing generated declarative config to JSON encoder: %v", err)
114+
}
115+
116+
if buf.String() == "" {
117+
return "", errors.New("file-based catalog contents cannot be empty")
118+
}
119+
120+
return buf.String(), nil
121+
}
122+
123+
// RenderRefs will invoke Operator Registry APIs and return a declarative config object representation
124+
// of the references that are passed in as a string array.
125+
func RenderRefs(ctx context.Context, refs []string) (*declarativeconfig.DeclarativeConfig, error) {
126+
render := action.Render{
127+
Refs: refs,
128+
}
129+
130+
log.SetOutput(ioutil.Discard)
131+
declcfg, err := render.Run(ctx)
132+
log.SetOutput(os.Stdout)
133+
if err != nil {
134+
return nil, fmt.Errorf("error in rendering the bundle and index image: %v", err)
135+
}
136+
137+
return declcfg, nil
138+
}
139+
140+
// IsFBC will determine if an index image uses the File-Based Catalog or SQLite index image format.
141+
// The default index image will adopt the File-Based Catalog format.
142+
func IsFBC(ctx context.Context, indexImage string) (bool, error) {
143+
// adding updates to the IndexImageCatalogCreator if it is an FBC image
144+
catalogLabels, err := registryutil.GetImageLabels(ctx, nil, indexImage, false)
145+
if err != nil {
146+
return false, fmt.Errorf("get index image labels: %v", err)
147+
}
148+
_, hasFBCLabel := catalogLabels[containertools.ConfigsLocationLabel]
149+
150+
return hasFBCLabel || indexImage == DefaultIndexImage, nil
151+
}

internal/olm/operator/bundle/install.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ import (
2727
"github.com/operator-framework/api/pkg/operators/v1alpha1"
2828
"github.com/operator-framework/operator-registry/alpha/action"
2929
declarativeconfig "github.com/operator-framework/operator-registry/alpha/declcfg"
30-
"github.com/operator-framework/operator-registry/pkg/containertools"
3130
registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle"
31+
fbcutil "github.com/operator-framework/operator-sdk/internal/olm/fbcutil"
3232
"github.com/operator-framework/operator-sdk/internal/olm/operator"
3333
"github.com/operator-framework/operator-sdk/internal/olm/operator/registry"
34-
registryutil "github.com/operator-framework/operator-sdk/internal/registry"
3534
)
3635

3736
type Install struct {
@@ -54,7 +53,7 @@ func NewInstall(cfg *operator.Configuration) Install {
5453
}
5554

5655
func (i *Install) BindFlags(fs *pflag.FlagSet) {
57-
fs.StringVar(&i.IndexImage, "index-image", registry.DefaultIndexImage, "index image in which to inject bundle")
56+
fs.StringVar(&i.IndexImage, "index-image", fbcutil.DefaultIndexImage, "index image in which to inject bundle")
5857
fs.Var(&i.InstallMode, "install-mode", "install mode")
5958

6059
// --mode is hidden so only users who know what they're doing can alter add mode.
@@ -95,15 +94,15 @@ func (i *Install) setup(ctx context.Context) error {
9594
return err
9695
}
9796

98-
// get index image labels.
99-
catalogLabels, err := registryutil.GetImageLabels(ctx, nil, i.IndexImageCatalogCreator.IndexImage, false)
97+
// check if index image adopts File-Based Catalog or SQLite index image format
98+
isFBCImage, err := fbcutil.IsFBC(ctx, i.IndexImageCatalogCreator.IndexImage)
10099
if err != nil {
101-
return fmt.Errorf("get index image labels: %v", err)
100+
return fmt.Errorf("error in upgrading the bundle %q that was installed traditionally", i.IndexImageCatalogCreator.BundleImage)
102101
}
102+
i.IndexImageCatalogCreator.HasFBCLabel = isFBCImage
103103

104104
// set the field to true if FBC label is on the image or for a default index image.
105-
if _, hasFBCLabel := catalogLabels[containertools.ConfigsLocationLabel]; hasFBCLabel || i.IndexImageCatalogCreator.IndexImage == registry.DefaultIndexImage {
106-
i.IndexImageCatalogCreator.HasFBCLabel = true
105+
if i.IndexImageCatalogCreator.HasFBCLabel {
107106
if i.IndexImageCatalogCreator.BundleAddMode != "" {
108107
return fmt.Errorf("specifying the bundle add mode is not supported for File-Based Catalog bundles and index images")
109108
}
@@ -115,7 +114,7 @@ func (i *Install) setup(ctx context.Context) error {
115114

116115
if i.IndexImageCatalogCreator.HasFBCLabel {
117116
// FBC variables
118-
f := &registry.FBCContext{
117+
f := &fbcutil.FBCContext{
119118
Package: labels[registrybundle.PackageLabel],
120119
Refs: []string{i.BundleImage},
121120
ChannelEntry: declarativeconfig.ChannelEntry{
@@ -126,7 +125,7 @@ func (i *Install) setup(ctx context.Context) error {
126125
if _, hasChannelMetadata := labels[registrybundle.ChannelsLabel]; hasChannelMetadata {
127126
f.ChannelName = strings.Split(labels[registrybundle.ChannelsLabel], ",")[0]
128127
} else {
129-
f.ChannelName = registry.DefaultChannel
128+
f.ChannelName = fbcutil.DefaultChannel
130129
}
131130

132131
// generate an fbc if an fbc specific label is found on the image or for a default index image.
@@ -151,7 +150,7 @@ func (i *Install) setup(ctx context.Context) error {
151150
}
152151

153152
// generateFBCContent creates a File-Based Catalog using the bundle image and index image from the run bundle command.
154-
func generateFBCContent(ctx context.Context, f *registry.FBCContext, bundleImage, indexImage string) (string, error) {
153+
func generateFBCContent(ctx context.Context, f *fbcutil.FBCContext, bundleImage, indexImage string) (string, error) {
155154
log.Infof("Creating a File-Based Catalog of the bundle %q", bundleImage)
156155
// generate a File-Based Catalog representation of the bundle image
157156
bundleDeclcfg, err := f.CreateFBC(ctx)
@@ -165,7 +164,7 @@ func generateFBCContent(ctx context.Context, f *registry.FBCContext, bundleImage
165164
Channels: []declarativeconfig.Channel{bundleDeclcfg.Channel},
166165
}
167166

168-
if indexImage != registry.DefaultIndexImage { // non-default index image was specified.
167+
if indexImage != fbcutil.DefaultIndexImage { // non-default index image was specified.
169168
// since an index image is specified, the bundle image will be added to the index image.
170169
// addBundleToIndexImage will ensure that the bundle is not already present in the index image and error out if it does.
171170
declcfg, err = addBundleToIndexImage(ctx, indexImage, bundleDeclcfg)
@@ -176,7 +175,7 @@ func generateFBCContent(ctx context.Context, f *registry.FBCContext, bundleImage
176175

177176
// validate the declarative config and convert it to a string
178177
var content string
179-
if content, err = registry.ValidateAndStringify(declcfg); err != nil {
178+
if content, err = fbcutil.ValidateAndStringify(declcfg); err != nil {
180179
return "", fmt.Errorf("error validating and converting the declarative config object to a string format: %v", err)
181180
}
182181

@@ -186,7 +185,7 @@ func generateFBCContent(ctx context.Context, f *registry.FBCContext, bundleImage
186185
}
187186

188187
// addBundleToIndexImage adds the bundle to an existing index image if the bundle is not already present in the index image.
189-
func addBundleToIndexImage(ctx context.Context, indexImage string, bundleDeclConfig registry.BundleDeclcfg) (*declarativeconfig.DeclarativeConfig, error) {
188+
func addBundleToIndexImage(ctx context.Context, indexImage string, bundleDeclConfig fbcutil.BundleDeclcfg) (*declarativeconfig.DeclarativeConfig, error) {
190189
log.Infof("Rendering a File-Based Catalog of the Index Image %q", indexImage)
191190
log.SetOutput(ioutil.Discard)
192191
render := action.Render{

internal/olm/operator/bundleupgrade/upgrade.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/operator-framework/api/pkg/operators/v1alpha1"
2222
registrybundle "github.com/operator-framework/operator-registry/pkg/lib/bundle"
23+
fbcutil "github.com/operator-framework/operator-sdk/internal/olm/fbcutil"
2324
"github.com/operator-framework/operator-sdk/internal/olm/operator"
2425
"github.com/operator-framework/operator-sdk/internal/olm/operator/registry"
2526
"github.com/spf13/pflag"
@@ -84,12 +85,12 @@ func (u *Upgrade) setup(ctx context.Context) error {
8485
// defer defaulting the bundle add mode to after the existing CatalogSource is retrieved.
8586
u.IndexImageCatalogCreator.PackageName = u.OperatorInstaller.PackageName
8687
u.IndexImageCatalogCreator.BundleImage = u.BundleImage
87-
u.IndexImageCatalogCreator.IndexImage = registry.DefaultIndexImage
88+
u.IndexImageCatalogCreator.IndexImage = fbcutil.DefaultIndexImage
8889

8990
if _, hasChannelMetadata := labels[registrybundle.ChannelsLabel]; hasChannelMetadata {
9091
u.IndexImageCatalogCreator.ChannelName = strings.Split(labels[registrybundle.ChannelsLabel], ",")[0]
9192
} else {
92-
u.IndexImageCatalogCreator.ChannelName = registry.DefaultChannel
93+
u.IndexImageCatalogCreator.ChannelName = fbcutil.DefaultChannel
9394
}
9495

9596
return nil

0 commit comments

Comments
 (0)