diff --git a/alpha/action/init.go b/alpha/action/init.go index 242d8f818..01998ee8d 100644 --- a/alpha/action/init.go +++ b/alpha/action/init.go @@ -43,7 +43,7 @@ func (i Init) Run() (*declcfg.Package, error) { if iconType.MIME.Type != "image" { return nil, fmt.Errorf("detected invalid type %q: not an image", iconType.MIME.Value) } - pkg.Icon = &declcfg.Icon{ + pkg.Icon = &declcfg.PackageIcon{ //nolint:staticcheck Data: iconData, MediaType: iconType.MIME.Value, } diff --git a/alpha/action/init_test.go b/alpha/action/init_test.go index 3825571d5..1e14a61e0 100644 --- a/alpha/action/init_test.go +++ b/alpha/action/init_test.go @@ -73,7 +73,7 @@ func TestInit(t *testing.T) { }, expectPkg: &declcfg.Package{ Schema: "olm.package", - Icon: &declcfg.Icon{ + Icon: &declcfg.PackageIcon{ Data: bytes.NewBufferString(svgIcon).Bytes(), MediaType: "image/svg+xml", }, @@ -93,7 +93,7 @@ func TestInit(t *testing.T) { Name: "a", DefaultChannel: "b", Description: "c", - Icon: &declcfg.Icon{ + Icon: &declcfg.PackageIcon{ Data: bytes.NewBufferString(svgIcon).Bytes(), MediaType: "image/svg+xml", }, diff --git a/alpha/action/migrations/001_split_icon.go b/alpha/action/migrations/001_split_icon.go new file mode 100644 index 000000000..cc611e389 --- /dev/null +++ b/alpha/action/migrations/001_split_icon.go @@ -0,0 +1,32 @@ +package migrations + +import ( + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +func splitIcon(cfg *declcfg.DeclarativeConfig) error { + splitIconFromPackage := func(p *declcfg.Package) error { + if p.Icon == nil { //nolint:staticcheck + return nil + } + + // Make separate olm.icon object + cfg.Icons = append(cfg.Icons, declcfg.Icon{ + Schema: declcfg.SchemaIcon, + Package: p.Name, + MediaType: p.Icon.MediaType, //nolint:staticcheck + Data: p.Icon.Data, //nolint:staticcheck + }) + + // Delete original icon from olm.package object + p.Icon = nil //nolint:staticcheck + return nil + } + + for i := range cfg.Packages { + if err := splitIconFromPackage(&cfg.Packages[i]); err != nil { + return err + } + } + return nil +} diff --git a/alpha/action/migrations/002_promote_bundle_version.go b/alpha/action/migrations/002_promote_bundle_version.go new file mode 100644 index 000000000..de9b931c4 --- /dev/null +++ b/alpha/action/migrations/002_promote_bundle_version.go @@ -0,0 +1,44 @@ +package migrations + +import ( + "encoding/json" + "slices" + + "github.com/Masterminds/semver/v3" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func promoteBundleVersion(cfg *declcfg.DeclarativeConfig) error { + promoteVersion := func(b *declcfg.Bundle) error { + // Promote the version from the olm.package property to the bundle field. + for _, p := range b.Properties { + if p.Type != property.TypePackage { + continue + } + var pkg property.Package + if err := json.Unmarshal(p.Value, &pkg); err != nil { + return err + } + version, err := semver.StrictNewVersion(pkg.Version) + if err != nil { + return err + } + b.Version = version + } + + // Delete the olm.package properties + b.Properties = slices.DeleteFunc(b.Properties, func(p property.Property) bool { + return p.Type == property.TypePackage + }) + return nil + } + + for i := range cfg.Bundles { + if err := promoteVersion(&cfg.Bundles[i]); err != nil { + return err + } + } + return nil +} diff --git a/alpha/action/migrations/003_promote_package_metadata.go b/alpha/action/migrations/003_promote_package_metadata.go new file mode 100644 index 000000000..618f66f31 --- /dev/null +++ b/alpha/action/migrations/003_promote_package_metadata.go @@ -0,0 +1,155 @@ +package migrations + +import ( + "encoding/json" + "slices" + "strings" + "unicode" + "unicode/utf8" + + "github.com/Masterminds/semver/v3" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func promotePackageMetadata(cfg *declcfg.DeclarativeConfig) error { + metadataByPackage := map[string]promotedMetadata{} + for i := range cfg.Bundles { + b := &cfg.Bundles[i] + + csvMetadata, csvMetadataIdx, err := getCsvMetadata(b) + if err != nil { + return err + } + + // Skip objects that have no olm.csv.metadata property + if csvMetadata == nil { + continue + } + + // Keep track of the metadata from the highest versioned bundle from each package. + cur, ok := metadataByPackage[b.Package] + if !ok || compareRegistryV1Semver(cur.version, b.Version) < 0 { + metadataByPackage[b.Package] = promotedCSVMetadata(b.Version, csvMetadata) + } + + // Delete the package-level metadata from the olm.csv.metadata object and + // update the bundle properties to use the new slimmed-down revision of it. + csvMetadata.DisplayName = "" + delete(csvMetadata.Annotations, "description") + csvMetadata.Provider = v1alpha1.AppLink{} + csvMetadata.Maintainers = nil + csvMetadata.Links = nil + csvMetadata.Keywords = nil + + newCSVMetadata, err := json.Marshal(csvMetadata) + if err != nil { + return err + } + b.Properties[csvMetadataIdx] = property.Property{ + Type: property.TypeCSVMetadata, + Value: newCSVMetadata, + } + } + + // Update each olm.package object to include the metadata we extracted from + // bundles in the first loop. + for i := range cfg.Packages { + pkg := &cfg.Packages[i] + metadata, ok := metadataByPackage[pkg.Name] + if !ok { + continue + } + pkg.DisplayName = metadata.displayName + pkg.ShortDescription = shortenDescription(metadata.shortDescription) + if metadata.provider.Name != "" || metadata.provider.URL != "" { + pkg.Provider = &metadata.provider + } + pkg.Maintainers = metadata.maintainers + pkg.Links = metadata.links + pkg.Keywords = slices.DeleteFunc(metadata.keywords, func(s string) bool { + // Delete keywords that are empty strings + return s == "" + }) + } + return nil +} + +func getCsvMetadata(b *declcfg.Bundle) (*property.CSVMetadata, int, error) { + for i, p := range b.Properties { + if p.Type != property.TypeCSVMetadata { + continue + } + var csvMetadata property.CSVMetadata + if err := json.Unmarshal(p.Value, &csvMetadata); err != nil { + return nil, -1, err + } + return &csvMetadata, i, nil + } + return nil, -1, nil +} + +func compareRegistryV1Semver(a, b *semver.Version) int { + if v := a.Compare(b); v != 0 { + return v + } + aPre := semver.New(0, 0, 0, a.Metadata(), "") + bPre := semver.New(0, 0, 0, b.Metadata(), "") + return aPre.Compare(bPre) +} + +type promotedMetadata struct { + version *semver.Version + + displayName string + shortDescription string + provider v1alpha1.AppLink + maintainers []v1alpha1.Maintainer + links []v1alpha1.AppLink + keywords []string +} + +func promotedCSVMetadata(version *semver.Version, metadata *property.CSVMetadata) promotedMetadata { + return promotedMetadata{ + version: version, + displayName: metadata.DisplayName, + shortDescription: metadata.Annotations["description"], + provider: metadata.Provider, + maintainers: metadata.Maintainers, + links: metadata.Links, + keywords: metadata.Keywords, + } +} + +func shortenDescription(input string) string { + const maxLen = 256 + input = strings.TrimSpace(input) + + // If the input is already under the limit return it. + if utf8.RuneCountInString(input) <= maxLen { + return input + } + + // Chop off everything after the first paragraph. + if idx := strings.Index(input, "\n\n"); idx != -1 { + input = strings.TrimSpace(input[:idx]) + } + + // If we're _now_ under the limit, return the first paragraph. + if utf8.RuneCountInString(input) <= maxLen { + return input + } + + // If the first paragraph is still over the limit, we'll have to truncate. + // We'll truncate at the last word boundary that still allows an ellipsis + // to fit within the maximum length. But if there are no word boundaries + // (veeeeery unlikely), we'll hard truncate mid-word. + input = input[:maxLen-3] + if truncatedIdx := strings.LastIndexFunc(input, unicode.IsSpace); truncatedIdx != -1 { + return input[:truncatedIdx] + "..." + } + return input + "..." +} diff --git a/alpha/action/migrations/migrations.go b/alpha/action/migrations/migrations.go index 22ff86b74..a6d5dc421 100644 --- a/alpha/action/migrations/migrations.go +++ b/alpha/action/migrations/migrations.go @@ -54,6 +54,9 @@ type Migrations struct { var allMigrations = []Migration{ newMigration(NoMigrations, "do nothing", func(_ *declcfg.DeclarativeConfig) error { return nil }), newMigration("bundle-object-to-csv-metadata", `migrates bundles' "olm.bundle.object" to "olm.csv.metadata"`, bundleObjectToCSVMetadata), + newMigration("split-icon", `split package icon out into separate "olm.icon" blob`, splitIcon), + newMigration("promote-bundle-version", `promote bundle version into first-class bundle field, remove olm.package properties`, promoteBundleVersion), + newMigration("promote-package-metadata", `promote package metadata from "olm.csv.metadata" properties to "olm.package" blob`, promotePackageMetadata), } func NewMigrations(name string) (*Migrations, error) { diff --git a/alpha/action/migrations/migrations_test.go b/alpha/action/migrations/migrations_test.go index d3b1ad074..4c11a474a 100644 --- a/alpha/action/migrations/migrations_test.go +++ b/alpha/action/migrations/migrations_test.go @@ -37,6 +37,9 @@ func TestMigrations(t *testing.T) { } return nil }, + MigrationToken("split-icon"): func(d *declcfg.DeclarativeConfig) error { return nil }, + MigrationToken("promote-bundle-version"): func(d *declcfg.DeclarativeConfig) error { return nil }, + MigrationToken("promote-package-metadata"): func(d *declcfg.DeclarativeConfig) error { return nil }, } tests := []struct { diff --git a/alpha/declcfg/declcfg.go b/alpha/declcfg/declcfg.go index 9e4f752ee..baec631cb 100644 --- a/alpha/declcfg/declcfg.go +++ b/alpha/declcfg/declcfg.go @@ -6,16 +6,20 @@ import ( "errors" "fmt" + "github.com/Masterminds/semver/v3" "golang.org/x/text/cases" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-registry/alpha/property" prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" ) const ( SchemaPackage = "olm.package" + SchemaIcon = "olm.icon" SchemaChannel = "olm.channel" SchemaBundle = "olm.bundle" SchemaDeprecation = "olm.deprecations" @@ -23,6 +27,7 @@ const ( type DeclarativeConfig struct { Packages []Package + Icons []Icon Channels []Channel Bundles []Bundle Deprecations []Deprecation @@ -30,15 +35,33 @@ type DeclarativeConfig struct { } type Package struct { - Schema string `json:"schema"` - Name string `json:"name"` - DefaultChannel string `json:"defaultChannel"` - Icon *Icon `json:"icon,omitempty"` - Description string `json:"description,omitempty"` - Properties []property.Property `json:"properties,omitempty" hash:"set"` + Schema string `json:"schema"` + Name string `json:"name"` + DisplayName string `json:"displayName,omitempty"` + ShortDescription string `json:"shortDescription,omitempty"` + Provider *v1alpha1.AppLink `json:"provider,omitempty"` + Maintainers []v1alpha1.Maintainer `json:"maintainers,omitempty"` + Links []v1alpha1.AppLink `json:"links,omitempty"` + Keywords []string `json:"keywords,omitempty"` + DefaultChannel string `json:"defaultChannel"` + + // Deprecated: It is no longer recommended to embed an icon in the package. + // Instead, use separate a Icon item alongside the Package. + Icon *PackageIcon `json:"icon,omitempty"` + + Description string `json:"description,omitempty"` + Properties []property.Property `json:"properties,omitempty" hash:"set"` } type Icon struct { + Schema string `json:"schema"` + Package string `json:"package"` + + MediaType string `json:"mediaType"` + Data []byte `json:"data"` +} + +type PackageIcon struct { Data []byte `json:"base64data"` MediaType string `json:"mediatype"` } @@ -69,8 +92,9 @@ type ChannelEntry struct { // evaluation in bundlesEqual(). type Bundle struct { Schema string `json:"schema"` - Name string `json:"name,omitempty"` - Package string `json:"package,omitempty"` + Name string `json:"name"` + Package string `json:"package"` + Version *semver.Version `json:"version,omitempty"` Image string `json:"image"` Properties []property.Property `json:"properties,omitempty" hash:"set"` RelatedImages []RelatedImage `json:"relatedImages,omitempty" hash:"set"` @@ -201,6 +225,7 @@ func extractUniqueMetaKeys(blobMap map[string]any, m *Meta) error { func (destination *DeclarativeConfig) Merge(src *DeclarativeConfig) { destination.Packages = append(destination.Packages, src.Packages...) + destination.Icons = append(destination.Icons, src.Icons...) destination.Channels = append(destination.Channels, src.Channels...) destination.Bundles = append(destination.Bundles, src.Bundles...) destination.Others = append(destination.Others, src.Others...) diff --git a/alpha/declcfg/declcfg_to_model.go b/alpha/declcfg/declcfg_to_model.go index 342cab403..a9015172f 100644 --- a/alpha/declcfg/declcfg_to_model.go +++ b/alpha/declcfg/declcfg_to_model.go @@ -31,6 +31,13 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) { Name: p.Name, Description: p.Description, Channels: map[string]*model.Channel{}, + + DisplayName: p.DisplayName, + ShortDescription: p.ShortDescription, + Provider: p.Provider, + Maintainers: p.Maintainers, + Links: p.Links, + Keywords: p.Keywords, } if p.Icon != nil { mpkg.Icon = &model.Icon{ @@ -41,6 +48,19 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) { defaultChannels[p.Name] = p.DefaultChannel mpkgs[p.Name] = mpkg } + for _, i := range cfg.Icons { + mpkg, ok := mpkgs[i.Package] + if !ok { + return nil, fmt.Errorf("unknown package %q found in olm.icon", i.Package) + } + if mpkg.Icon != nil { + return nil, fmt.Errorf("duplicate icon found for package %q; expecting no more than one icon per package", i.Package) + } + mpkg.Icon = &model.Icon{ + MediaType: i.MediaType, + Data: i.Data, + } + } channelDefinedEntries := map[string]sets.Set[string]{} for _, c := range cfg.Channels { @@ -120,16 +140,18 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) { return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err) } - if len(props.Packages) != 1 { - return nil, fmt.Errorf("package %q bundle %q must have exactly 1 %q property, found %d", b.Package, b.Name, property.TypePackage, len(props.Packages)) - } - - if b.Package != props.Packages[0].PackageName { - return nil, fmt.Errorf("package %q does not match %q property %q", b.Package, property.TypePackage, props.Packages[0].PackageName) + var rawVersion string + if b.Version != nil { + rawVersion = b.Version.String() + } else if len(props.Packages) == 1 { + if b.Package != props.Packages[0].PackageName { + return nil, fmt.Errorf("package %q does not match %q property %q", b.Package, property.TypePackage, props.Packages[0].PackageName) + } + rawVersion = props.Packages[0].Version + } else { + return nil, fmt.Errorf("package %q bundle %q requires either version being set or exactly one property with type %q", b.Package, b.Name, property.TypePackage) } - // Parse version from the package property. - rawVersion := props.Packages[0].Version ver, err := semver.Parse(rawVersion) if err != nil { return nil, fmt.Errorf("error parsing bundle %q version %q: %v", b.Name, rawVersion, err) diff --git a/alpha/declcfg/declcfg_to_model_test.go b/alpha/declcfg/declcfg_to_model_test.go index de8639c1b..05a108aeb 100644 --- a/alpha/declcfg/declcfg_to_model_test.go +++ b/alpha/declcfg/declcfg_to_model_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + mmsemver "github.com/Masterminds/semver/v3" "github.com/blang/semver/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -120,8 +121,8 @@ func TestConvertToModel(t *testing.T) { }, }, { - name: "Error/BundleMissingPackageProperty", - assertion: hasError(`package "foo" bundle "foo.v0.1.0" must have exactly 1 "olm.package" property, found 0`), + name: "Error/BundleMissingVersionAndPackageProperty", + assertion: hasError(`package "foo" bundle "foo.v0.1.0" requires either version being set or exactly one property with type "olm.package"`), cfg: DeclarativeConfig{ Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, Bundles: []Bundle{newTestBundle("foo", "0.1.0", withNoProperties())}, @@ -129,7 +130,7 @@ func TestConvertToModel(t *testing.T) { }, { name: "Error/BundleMultiplePackageProperty", - assertion: hasError(`package "foo" bundle "foo.v0.1.0" must have exactly 1 "olm.package" property, found 2`), + assertion: hasError(`package "foo" bundle "foo.v0.1.0" requires either version being set or exactly one property with type "olm.package"`), cfg: DeclarativeConfig{ Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, Bundles: []Bundle{newTestBundle("foo", "0.1.0", func(b *Bundle) { @@ -140,6 +141,15 @@ func TestConvertToModel(t *testing.T) { })}, }, }, + { + name: "Success/BundleWithVersionButNoProperties", + assertion: require.NoError, + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: testBundleName("foo", "0.1.0")})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", withVersionField(mmsemver.MustParse("0.1.0")), withNoProperties())}, + }, + }, { name: "Success/BundleWithDataButMissingImage", assertion: require.NoError, diff --git a/alpha/declcfg/helpers_test.go b/alpha/declcfg/helpers_test.go index 1d55f9e2a..e90bd71b1 100644 --- a/alpha/declcfg/helpers_test.go +++ b/alpha/declcfg/helpers_test.go @@ -6,7 +6,8 @@ import ( "sort" "testing" - "github.com/blang/semver/v4" + mmsemver "github.com/Masterminds/semver/v3" + bsemver "github.com/blang/semver/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -126,6 +127,12 @@ func buildValidDeclarativeConfig(spec validDeclarativeConfigSpec) DeclarativeCon type bundleOpt func(*Bundle) +func withVersionField(version *mmsemver.Version) func(*Bundle) { + return func(bundle *Bundle) { + bundle.Version = version + } +} + func withNoProperties() func(*Bundle) { return func(b *Bundle) { b.Properties = []property.Property{} @@ -147,6 +154,7 @@ func withNoBundleData() func(*Bundle) { func newTestBundle(packageName, version string, opts ...bundleOpt) Bundle { csvJSON := fmt.Sprintf(`{"kind": "ClusterServiceVersion", "apiVersion": "operators.coreos.com/v1alpha1", "metadata":{"name":%q}}`, testBundleName(packageName, version)) + b := Bundle{ Schema: SchemaBundle, Name: testBundleName(packageName, version), @@ -191,7 +199,7 @@ func newTestPackage(packageName, defaultChannel, svgData string) Package { Schema: SchemaPackage, Name: packageName, DefaultChannel: defaultChannel, - Icon: &Icon{Data: []byte(svgData), MediaType: "image/svg+xml"}, + Icon: &PackageIcon{Data: []byte(svgData), MediaType: "image/svg+xml"}, Description: testPackageDescription(packageName), } return p @@ -245,7 +253,7 @@ func getBundle(pkg *model.Package, ch *model.Channel, version, replaces string, getCSVJson(pkg.Name, version), getCRDJSON(), }, - Version: semver.MustParse(version), + Version: bsemver.MustParse(version), } } diff --git a/alpha/declcfg/load.go b/alpha/declcfg/load.go index 5db111b87..722b3b404 100644 --- a/alpha/declcfg/load.go +++ b/alpha/declcfg/load.go @@ -279,6 +279,7 @@ type fbcBuilder struct { cfg DeclarativeConfig packagesMu sync.Mutex + iconsMu sync.Mutex channelsMu sync.Mutex bundlesMu sync.Mutex deprecationsMu sync.Mutex @@ -295,6 +296,14 @@ func (c *fbcBuilder) addMeta(in *Meta) error { c.packagesMu.Lock() c.cfg.Packages = append(c.cfg.Packages, p) c.packagesMu.Unlock() + case SchemaIcon: + var i Icon + if err := json.Unmarshal(in.Blob, &i); err != nil { + return fmt.Errorf("parse icon: %v", err) + } + c.iconsMu.Lock() + c.cfg.Icons = append(c.cfg.Icons, i) + c.iconsMu.Unlock() case SchemaChannel: var ch Channel if err := json.Unmarshal(in.Blob, &ch); err != nil { diff --git a/alpha/declcfg/load_benchmark_test.go b/alpha/declcfg/load_benchmark_test.go index 46f3138be..11a2db059 100644 --- a/alpha/declcfg/load_benchmark_test.go +++ b/alpha/declcfg/load_benchmark_test.go @@ -59,7 +59,7 @@ func generateFBC(b *testing.B, numPackages, numChannels, numBundles int) *declcf Schema: declcfg.SchemaPackage, Name: pkgName, Description: fmt.Sprintf("%s description", pkgName), - Icon: &declcfg.Icon{ + Icon: &declcfg.PackageIcon{ Data: pngData, MediaType: "image/png", }, diff --git a/alpha/declcfg/load_test.go b/alpha/declcfg/load_test.go index 392fbd795..1c017f5e0 100644 --- a/alpha/declcfg/load_test.go +++ b/alpha/declcfg/load_test.go @@ -199,8 +199,8 @@ func TestLoadFS(t *testing.T) { assertion: require.NoError, expected: &DeclarativeConfig{ Packages: []Package{ - {Schema: "olm.package", Name: "cockroachdb", DefaultChannel: "stable-5.x", Icon: &Icon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x33, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x33, 0x32, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x34, 0x38, 0x36, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x43, 0x4c, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x39, 0x2e, 0x34, 0x32, 0x20, 0x39, 0x2e, 0x31, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x33, 0x2e, 0x39, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x20, 0x33, 0x2e, 0x39, 0x31, 0x7a, 0x4d, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x39, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x36, 0x38, 0x20, 0x32, 0x2e, 0x39, 0x33, 0x41, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x36, 0x2e, 0x32, 0x33, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x34, 0x2e, 0x34, 0x34, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2e, 0x31, 0x33, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x38, 0x33, 0x20, 0x31, 0x2e, 0x35, 0x37, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x35, 0x39, 0x20, 0x31, 0x2e, 0x38, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x20, 0x34, 0x2e, 0x34, 0x38, 0x63, 0x2d, 0x2e, 0x32, 0x2e, 0x33, 0x32, 0x2d, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x35, 0x2d, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x33, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x2d, 0x2e, 0x34, 0x34, 0x20, 0x31, 0x2e, 0x30, 0x38, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x34, 0x2e, 0x32, 0x39, 0x20, 0x31, 0x38, 0x2e, 0x37, 0x63, 0x2e, 0x32, 0x36, 0x2e, 0x32, 0x35, 0x2e, 0x35, 0x33, 0x2e, 0x34, 0x39, 0x2e, 0x38, 0x31, 0x2e, 0x37, 0x33, 0x73, 0x2e, 0x34, 0x34, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x37, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x39, 0x2e, 0x34, 0x34, 0x2e, 0x38, 0x39, 0x2e, 0x36, 0x34, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x63, 0x2e, 0x33, 0x2d, 0x2e, 0x32, 0x31, 0x2e, 0x36, 0x2d, 0x2e, 0x34, 0x32, 0x2e, 0x38, 0x39, 0x2d, 0x2e, 0x36, 0x34, 0x73, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x2d, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x35, 0x2d, 0x2e, 0x34, 0x38, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x37, 0x33, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x35, 0x2e, 0x33, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x2d, 0x36, 0x2e, 0x30, 0x39, 0x63, 0x2d, 0x2e, 0x31, 0x34, 0x2d, 0x2e, 0x33, 0x37, 0x2d, 0x2e, 0x32, 0x39, 0x2d, 0x2e, 0x37, 0x33, 0x2d, 0x2e, 0x34, 0x35, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2d, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x33, 0x33, 0x2d, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x35, 0x2d, 0x2e, 0x36, 0x36, 0x2d, 0x2e, 0x35, 0x35, 0x2d, 0x31, 0x61, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x2d, 0x34, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2e, 0x35, 0x34, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x71, 0x2e, 0x34, 0x34, 0x2d, 0x2e, 0x37, 0x36, 0x2e, 0x38, 0x32, 0x2d, 0x31, 0x2e, 0x35, 0x36, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x2e, 0x30, 0x39, 0x41, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x31, 0x35, 0x31, 0x66, 0x33, 0x34, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x34, 0x2e, 0x32, 0x35, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x2d, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x34, 0x2e, 0x32, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x33, 0x34, 0x38, 0x35, 0x34, 0x30, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x33, 0x2d, 0x31, 0x35, 0x2e, 0x33, 0x37, 0x41, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x37, 0x64, 0x62, 0x63, 0x34, 0x32, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e}, MediaType: "image/svg+xml"}, Description: ""}, - {Schema: "olm.package", Name: "etcd", DefaultChannel: "singlenamespace-alpha", Icon: &Icon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x34, 0x32, 0x32, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x36, 0x20, 0x32, 0x34, 0x38, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x22, 0x78, 0x4d, 0x69, 0x64, 0x59, 0x4d, 0x69, 0x64, 0x22, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x35, 0x32, 0x2e, 0x33, 0x38, 0x36, 0x20, 0x31, 0x32, 0x38, 0x2e, 0x30, 0x36, 0x34, 0x63, 0x2d, 0x31, 0x2e, 0x32, 0x30, 0x32, 0x2e, 0x31, 0x2d, 0x32, 0x2e, 0x34, 0x31, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x37, 0x2e, 0x34, 0x34, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x34, 0x2e, 0x36, 0x37, 0x2d, 0x31, 0x2e, 0x37, 0x34, 0x36, 0x2d, 0x32, 0x31, 0x2e, 0x31, 0x38, 0x37, 0x2d, 0x34, 0x2e, 0x39, 0x34, 0x34, 0x20, 0x32, 0x2e, 0x31, 0x37, 0x2d, 0x31, 0x32, 0x2e, 0x34, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x30, 0x39, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x39, 0x38, 0x37, 0x20, 0x32, 0x2e, 0x38, 0x35, 0x2d, 0x33, 0x37, 0x2e, 0x34, 0x38, 0x31, 0x2d, 0x37, 0x2e, 0x30, 0x36, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x32, 0x32, 0x2d, 0x31, 0x35, 0x2e, 0x31, 0x34, 0x2d, 0x31, 0x39, 0x2e, 0x38, 0x36, 0x33, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x35, 0x36, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x39, 0x35, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x31, 0x35, 0x20, 0x39, 0x2e, 0x38, 0x30, 0x31, 0x2d, 0x31, 0x33, 0x2e, 0x37, 0x39, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x2d, 0x31, 0x38, 0x2e, 0x33, 0x31, 0x39, 0x6c, 0x33, 0x2e, 0x31, 0x33, 0x33, 0x2d, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x32, 0x2d, 0x32, 0x2e, 0x37, 0x35, 0x34, 0x63, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x38, 0x31, 0x2d, 0x31, 0x34, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x32, 0x37, 0x2e, 0x35, 0x39, 0x36, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x2d, 0x34, 0x34, 0x2e, 0x36, 0x32, 0x2d, 0x33, 0x32, 0x2e, 0x35, 0x35, 0x32, 0x4c, 0x31, 0x37, 0x35, 0x2e, 0x38, 0x37, 0x36, 0x20, 0x30, 0x6c, 0x2d, 0x2e, 0x38, 0x36, 0x32, 0x20, 0x33, 0x2e, 0x35, 0x38, 0x38, 0x63, 0x2d, 0x32, 0x2e, 0x30, 0x33, 0x20, 0x38, 0x2e, 0x33, 0x36, 0x33, 0x2d, 0x36, 0x2e, 0x32, 0x37, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x39, 0x30, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x31, 0x20, 0x32, 0x31, 0x2e, 0x39, 0x36, 0x32, 0x61, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x34, 0x2e, 0x39, 0x35, 0x36, 0x2d, 0x31, 0x34, 0x2e, 0x34, 0x30, 0x35, 0x41, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x39, 0x33, 0x2e, 0x30, 0x35, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x32, 0x43, 0x38, 0x37, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x37, 0x33, 0x20, 0x38, 0x33, 0x2e, 0x30, 0x32, 0x20, 0x31, 0x31, 0x2e, 0x39, 0x34, 0x37, 0x20, 0x38, 0x30, 0x2e, 0x39, 0x39, 0x39, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x38, 0x4c, 0x38, 0x30, 0x2e, 0x31, 0x33, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x33, 0x2e, 0x33, 0x38, 0x32, 0x20, 0x31, 0x2e, 0x34, 0x37, 0x43, 0x35, 0x39, 0x2e, 0x39, 0x33, 0x39, 0x20, 0x38, 0x2e, 0x38, 0x31, 0x35, 0x20, 0x34, 0x34, 0x2e, 0x35, 0x31, 0x20, 0x32, 0x30, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x33, 0x32, 0x2e, 0x31, 0x33, 0x35, 0x20, 0x33, 0x34, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x39, 0x20, 0x32, 0x2e, 0x37, 0x36, 0x20, 0x33, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x63, 0x37, 0x2e, 0x32, 0x37, 0x36, 0x20, 0x34, 0x2e, 0x35, 0x30, 0x36, 0x20, 0x31, 0x33, 0x2e, 0x31, 0x30, 0x36, 0x20, 0x31, 0x30, 0x2e, 0x38, 0x34, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x30, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x32, 0x32, 0x33, 0x2d, 0x39, 0x2e, 0x30, 0x38, 0x38, 0x20, 0x38, 0x2e, 0x38, 0x35, 0x2d, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x34, 0x36, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x31, 0x34, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x33, 0x35, 0x2d, 0x2e, 0x32, 0x37, 0x35, 0x20, 0x31, 0x32, 0x2e, 0x34, 0x38, 0x39, 0x2e, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x20, 0x32, 0x2e, 0x37, 0x38, 0x20, 0x33, 0x37, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x2e, 0x34, 0x38, 0x34, 0x20, 0x33, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x31, 0x33, 0x2e, 0x36, 0x36, 0x38, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x32, 0x31, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x31, 0x2e, 0x32, 0x39, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x2d, 0x2e, 0x30, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2d, 0x2e, 0x31, 0x34, 0x35, 0x4c, 0x30, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x37, 0x38, 0x35, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x20, 0x33, 0x2e, 0x36, 0x37, 0x31, 0x63, 0x31, 0x2e, 0x38, 0x30, 0x32, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x37, 0x2e, 0x35, 0x37, 0x20, 0x33, 0x36, 0x2e, 0x32, 0x34, 0x37, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x35, 0x32, 0x2e, 0x35, 0x32, 0x33, 0x6c, 0x31, 0x2e, 0x38, 0x37, 0x20, 0x33, 0x2e, 0x31, 0x37, 0x36, 0x20, 0x32, 0x2e, 0x38, 0x31, 0x2d, 0x32, 0x2e, 0x33, 0x38, 0x34, 0x61, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x37, 0x33, 0x37, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x36, 0x20, 0x33, 0x31, 0x2e, 0x36, 0x39, 0x36, 0x63, 0x31, 0x31, 0x2e, 0x38, 0x32, 0x38, 0x20, 0x34, 0x2e, 0x31, 0x33, 0x37, 0x20, 0x32, 0x34, 0x2e, 0x31, 0x35, 0x31, 0x20, 0x37, 0x2e, 0x32, 0x32, 0x35, 0x20, 0x33, 0x36, 0x2e, 0x38, 0x37, 0x38, 0x20, 0x39, 0x2e, 0x30, 0x36, 0x33, 0x20, 0x31, 0x2e, 0x32, 0x32, 0x20, 0x38, 0x2e, 0x34, 0x31, 0x37, 0x2e, 0x32, 0x34, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x32, 0x32, 0x2d, 0x33, 0x2e, 0x30, 0x37, 0x32, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x37, 0x31, 0x6c, 0x2d, 0x31, 0x2e, 0x34, 0x20, 0x33, 0x2e, 0x34, 0x31, 0x31, 0x20, 0x33, 0x2e, 0x36, 0x2e, 0x37, 0x39, 0x33, 0x63, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x32, 0x2e, 0x30, 0x32, 0x37, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x32, 0x33, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x32, 0x37, 0x2e, 0x36, 0x33, 0x31, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x6c, 0x32, 0x37, 0x2e, 0x36, 0x32, 0x33, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x34, 0x2d, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x31, 0x2e, 0x34, 0x30, 0x33, 0x2d, 0x33, 0x2e, 0x34, 0x31, 0x37, 0x63, 0x2d, 0x33, 0x2e, 0x33, 0x31, 0x32, 0x2d, 0x38, 0x2e, 0x30, 0x35, 0x2d, 0x34, 0x2e, 0x32, 0x38, 0x34, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x33, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x38, 0x33, 0x20, 0x31, 0x32, 0x2e, 0x36, 0x37, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x32, 0x34, 0x2e, 0x39, 0x35, 0x34, 0x2d, 0x34, 0x2e, 0x39, 0x32, 0x20, 0x33, 0x36, 0x2e, 0x37, 0x33, 0x38, 0x2d, 0x39, 0x2e, 0x30, 0x34, 0x35, 0x61, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x38, 0x32, 0x2d, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x36, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x38, 0x34, 0x38, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x36, 0x6c, 0x32, 0x2e, 0x38, 0x30, 0x39, 0x20, 0x32, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x2e, 0x38, 0x36, 0x32, 0x2d, 0x33, 0x2e, 0x31, 0x36, 0x38, 0x63, 0x39, 0x2e, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x32, 0x39, 0x37, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x36, 0x38, 0x2d, 0x33, 0x33, 0x2e, 0x39, 0x36, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x34, 0x32, 0x2d, 0x35, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x31, 0x34, 0x2e, 0x32, 0x37, 0x39, 0x7a, 0x4d, 0x31, 0x36, 0x37, 0x2e, 0x34, 0x39, 0x20, 0x31, 0x37, 0x32, 0x2e, 0x39, 0x36, 0x63, 0x2d, 0x31, 0x33, 0x2e, 0x30, 0x36, 0x38, 0x20, 0x33, 0x2e, 0x35, 0x35, 0x34, 0x2d, 0x32, 0x36, 0x2e, 0x33, 0x34, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x33, 0x32, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x31, 0x33, 0x2e, 0x32, 0x32, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x36, 0x2e, 0x34, 0x38, 0x33, 0x2d, 0x31, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x36, 0x33, 0x2d, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x61, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x33, 0x32, 0x2d, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x63, 0x2d, 0x34, 0x2e, 0x30, 0x36, 0x36, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x31, 0x37, 0x2d, 0x36, 0x2e, 0x34, 0x34, 0x35, 0x2d, 0x32, 0x35, 0x2e, 0x36, 0x33, 0x2d, 0x37, 0x2e, 0x31, 0x33, 0x35, 0x2d, 0x33, 0x39, 0x2e, 0x31, 0x33, 0x34, 0x20, 0x38, 0x2e, 0x34, 0x34, 0x36, 0x2d, 0x31, 0x30, 0x2e, 0x34, 0x34, 0x33, 0x20, 0x31, 0x38, 0x2e, 0x30, 0x35, 0x32, 0x2d, 0x31, 0x39, 0x2e, 0x35, 0x39, 0x31, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x32, 0x37, 0x2e, 0x32, 0x39, 0x33, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x39, 0x36, 0x35, 0x2d, 0x31, 0x39, 0x2e, 0x30, 0x31, 0x31, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x38, 0x39, 0x38, 0x20, 0x31, 0x38, 0x2e, 0x39, 0x37, 0x63, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x34, 0x20, 0x37, 0x2e, 0x37, 0x34, 0x33, 0x20, 0x32, 0x30, 0x2e, 0x33, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x39, 0x36, 0x32, 0x20, 0x32, 0x38, 0x2e, 0x37, 0x39, 0x20, 0x32, 0x37, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x37, 0x32, 0x34, 0x20, 0x31, 0x33, 0x2e, 0x34, 0x32, 0x37, 0x2d, 0x33, 0x2e, 0x31, 0x33, 0x32, 0x20, 0x32, 0x36, 0x2e, 0x34, 0x36, 0x35, 0x2d, 0x37, 0x2e, 0x32, 0x30, 0x34, 0x20, 0x33, 0x38, 0x2e, 0x39, 0x36, 0x31, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x35, 0x32, 0x20, 0x33, 0x35, 0x2e, 0x37, 0x30, 0x37, 0x7a, 0x6d, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x32, 0x2e, 0x39, 0x39, 0x38, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x20, 0x37, 0x2e, 0x34, 0x38, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x39, 0x2e, 0x32, 0x31, 0x37, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x36, 0x2d, 0x37, 0x2e, 0x34, 0x37, 0x33, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x7a, 0x6d, 0x2d, 0x32, 0x31, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x30, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x2d, 0x37, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x33, 0x20, 0x37, 0x2e, 0x34, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x34, 0x31, 0x39, 0x45, 0x44, 0x41, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e, 0xa}, MediaType: "image/svg+xml"}, Description: "A message about etcd operator, a description of channels"}, + {Schema: "olm.package", Name: "cockroachdb", DefaultChannel: "stable-5.x", Icon: &PackageIcon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x33, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x33, 0x32, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x34, 0x38, 0x36, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x43, 0x4c, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x39, 0x2e, 0x34, 0x32, 0x20, 0x39, 0x2e, 0x31, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x33, 0x2e, 0x39, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x20, 0x33, 0x2e, 0x39, 0x31, 0x7a, 0x4d, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x39, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x36, 0x38, 0x20, 0x32, 0x2e, 0x39, 0x33, 0x41, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x36, 0x2e, 0x32, 0x33, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x34, 0x2e, 0x34, 0x34, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2e, 0x31, 0x33, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x38, 0x33, 0x20, 0x31, 0x2e, 0x35, 0x37, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x35, 0x39, 0x20, 0x31, 0x2e, 0x38, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x20, 0x34, 0x2e, 0x34, 0x38, 0x63, 0x2d, 0x2e, 0x32, 0x2e, 0x33, 0x32, 0x2d, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x35, 0x2d, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x33, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x2d, 0x2e, 0x34, 0x34, 0x20, 0x31, 0x2e, 0x30, 0x38, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x34, 0x2e, 0x32, 0x39, 0x20, 0x31, 0x38, 0x2e, 0x37, 0x63, 0x2e, 0x32, 0x36, 0x2e, 0x32, 0x35, 0x2e, 0x35, 0x33, 0x2e, 0x34, 0x39, 0x2e, 0x38, 0x31, 0x2e, 0x37, 0x33, 0x73, 0x2e, 0x34, 0x34, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x37, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x39, 0x2e, 0x34, 0x34, 0x2e, 0x38, 0x39, 0x2e, 0x36, 0x34, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x63, 0x2e, 0x33, 0x2d, 0x2e, 0x32, 0x31, 0x2e, 0x36, 0x2d, 0x2e, 0x34, 0x32, 0x2e, 0x38, 0x39, 0x2d, 0x2e, 0x36, 0x34, 0x73, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x2d, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x35, 0x2d, 0x2e, 0x34, 0x38, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x37, 0x33, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x35, 0x2e, 0x33, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x2d, 0x36, 0x2e, 0x30, 0x39, 0x63, 0x2d, 0x2e, 0x31, 0x34, 0x2d, 0x2e, 0x33, 0x37, 0x2d, 0x2e, 0x32, 0x39, 0x2d, 0x2e, 0x37, 0x33, 0x2d, 0x2e, 0x34, 0x35, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2d, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x33, 0x33, 0x2d, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x35, 0x2d, 0x2e, 0x36, 0x36, 0x2d, 0x2e, 0x35, 0x35, 0x2d, 0x31, 0x61, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x2d, 0x34, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2e, 0x35, 0x34, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x71, 0x2e, 0x34, 0x34, 0x2d, 0x2e, 0x37, 0x36, 0x2e, 0x38, 0x32, 0x2d, 0x31, 0x2e, 0x35, 0x36, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x2e, 0x30, 0x39, 0x41, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x31, 0x35, 0x31, 0x66, 0x33, 0x34, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x34, 0x2e, 0x32, 0x35, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x2d, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x34, 0x2e, 0x32, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x33, 0x34, 0x38, 0x35, 0x34, 0x30, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x33, 0x2d, 0x31, 0x35, 0x2e, 0x33, 0x37, 0x41, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x37, 0x64, 0x62, 0x63, 0x34, 0x32, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e}, MediaType: "image/svg+xml"}, Description: ""}, + {Schema: "olm.package", Name: "etcd", DefaultChannel: "singlenamespace-alpha", Icon: &PackageIcon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x34, 0x32, 0x32, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x36, 0x20, 0x32, 0x34, 0x38, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x22, 0x78, 0x4d, 0x69, 0x64, 0x59, 0x4d, 0x69, 0x64, 0x22, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x35, 0x32, 0x2e, 0x33, 0x38, 0x36, 0x20, 0x31, 0x32, 0x38, 0x2e, 0x30, 0x36, 0x34, 0x63, 0x2d, 0x31, 0x2e, 0x32, 0x30, 0x32, 0x2e, 0x31, 0x2d, 0x32, 0x2e, 0x34, 0x31, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x37, 0x2e, 0x34, 0x34, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x34, 0x2e, 0x36, 0x37, 0x2d, 0x31, 0x2e, 0x37, 0x34, 0x36, 0x2d, 0x32, 0x31, 0x2e, 0x31, 0x38, 0x37, 0x2d, 0x34, 0x2e, 0x39, 0x34, 0x34, 0x20, 0x32, 0x2e, 0x31, 0x37, 0x2d, 0x31, 0x32, 0x2e, 0x34, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x30, 0x39, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x39, 0x38, 0x37, 0x20, 0x32, 0x2e, 0x38, 0x35, 0x2d, 0x33, 0x37, 0x2e, 0x34, 0x38, 0x31, 0x2d, 0x37, 0x2e, 0x30, 0x36, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x32, 0x32, 0x2d, 0x31, 0x35, 0x2e, 0x31, 0x34, 0x2d, 0x31, 0x39, 0x2e, 0x38, 0x36, 0x33, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x35, 0x36, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x39, 0x35, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x31, 0x35, 0x20, 0x39, 0x2e, 0x38, 0x30, 0x31, 0x2d, 0x31, 0x33, 0x2e, 0x37, 0x39, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x2d, 0x31, 0x38, 0x2e, 0x33, 0x31, 0x39, 0x6c, 0x33, 0x2e, 0x31, 0x33, 0x33, 0x2d, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x32, 0x2d, 0x32, 0x2e, 0x37, 0x35, 0x34, 0x63, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x38, 0x31, 0x2d, 0x31, 0x34, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x32, 0x37, 0x2e, 0x35, 0x39, 0x36, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x2d, 0x34, 0x34, 0x2e, 0x36, 0x32, 0x2d, 0x33, 0x32, 0x2e, 0x35, 0x35, 0x32, 0x4c, 0x31, 0x37, 0x35, 0x2e, 0x38, 0x37, 0x36, 0x20, 0x30, 0x6c, 0x2d, 0x2e, 0x38, 0x36, 0x32, 0x20, 0x33, 0x2e, 0x35, 0x38, 0x38, 0x63, 0x2d, 0x32, 0x2e, 0x30, 0x33, 0x20, 0x38, 0x2e, 0x33, 0x36, 0x33, 0x2d, 0x36, 0x2e, 0x32, 0x37, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x39, 0x30, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x31, 0x20, 0x32, 0x31, 0x2e, 0x39, 0x36, 0x32, 0x61, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x34, 0x2e, 0x39, 0x35, 0x36, 0x2d, 0x31, 0x34, 0x2e, 0x34, 0x30, 0x35, 0x41, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x39, 0x33, 0x2e, 0x30, 0x35, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x32, 0x43, 0x38, 0x37, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x37, 0x33, 0x20, 0x38, 0x33, 0x2e, 0x30, 0x32, 0x20, 0x31, 0x31, 0x2e, 0x39, 0x34, 0x37, 0x20, 0x38, 0x30, 0x2e, 0x39, 0x39, 0x39, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x38, 0x4c, 0x38, 0x30, 0x2e, 0x31, 0x33, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x33, 0x2e, 0x33, 0x38, 0x32, 0x20, 0x31, 0x2e, 0x34, 0x37, 0x43, 0x35, 0x39, 0x2e, 0x39, 0x33, 0x39, 0x20, 0x38, 0x2e, 0x38, 0x31, 0x35, 0x20, 0x34, 0x34, 0x2e, 0x35, 0x31, 0x20, 0x32, 0x30, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x33, 0x32, 0x2e, 0x31, 0x33, 0x35, 0x20, 0x33, 0x34, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x39, 0x20, 0x32, 0x2e, 0x37, 0x36, 0x20, 0x33, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x63, 0x37, 0x2e, 0x32, 0x37, 0x36, 0x20, 0x34, 0x2e, 0x35, 0x30, 0x36, 0x20, 0x31, 0x33, 0x2e, 0x31, 0x30, 0x36, 0x20, 0x31, 0x30, 0x2e, 0x38, 0x34, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x30, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x32, 0x32, 0x33, 0x2d, 0x39, 0x2e, 0x30, 0x38, 0x38, 0x20, 0x38, 0x2e, 0x38, 0x35, 0x2d, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x34, 0x36, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x31, 0x34, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x33, 0x35, 0x2d, 0x2e, 0x32, 0x37, 0x35, 0x20, 0x31, 0x32, 0x2e, 0x34, 0x38, 0x39, 0x2e, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x20, 0x32, 0x2e, 0x37, 0x38, 0x20, 0x33, 0x37, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x2e, 0x34, 0x38, 0x34, 0x20, 0x33, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x31, 0x33, 0x2e, 0x36, 0x36, 0x38, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x32, 0x31, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x31, 0x2e, 0x32, 0x39, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x2d, 0x2e, 0x30, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2d, 0x2e, 0x31, 0x34, 0x35, 0x4c, 0x30, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x37, 0x38, 0x35, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x20, 0x33, 0x2e, 0x36, 0x37, 0x31, 0x63, 0x31, 0x2e, 0x38, 0x30, 0x32, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x37, 0x2e, 0x35, 0x37, 0x20, 0x33, 0x36, 0x2e, 0x32, 0x34, 0x37, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x35, 0x32, 0x2e, 0x35, 0x32, 0x33, 0x6c, 0x31, 0x2e, 0x38, 0x37, 0x20, 0x33, 0x2e, 0x31, 0x37, 0x36, 0x20, 0x32, 0x2e, 0x38, 0x31, 0x2d, 0x32, 0x2e, 0x33, 0x38, 0x34, 0x61, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x37, 0x33, 0x37, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x36, 0x20, 0x33, 0x31, 0x2e, 0x36, 0x39, 0x36, 0x63, 0x31, 0x31, 0x2e, 0x38, 0x32, 0x38, 0x20, 0x34, 0x2e, 0x31, 0x33, 0x37, 0x20, 0x32, 0x34, 0x2e, 0x31, 0x35, 0x31, 0x20, 0x37, 0x2e, 0x32, 0x32, 0x35, 0x20, 0x33, 0x36, 0x2e, 0x38, 0x37, 0x38, 0x20, 0x39, 0x2e, 0x30, 0x36, 0x33, 0x20, 0x31, 0x2e, 0x32, 0x32, 0x20, 0x38, 0x2e, 0x34, 0x31, 0x37, 0x2e, 0x32, 0x34, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x32, 0x32, 0x2d, 0x33, 0x2e, 0x30, 0x37, 0x32, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x37, 0x31, 0x6c, 0x2d, 0x31, 0x2e, 0x34, 0x20, 0x33, 0x2e, 0x34, 0x31, 0x31, 0x20, 0x33, 0x2e, 0x36, 0x2e, 0x37, 0x39, 0x33, 0x63, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x32, 0x2e, 0x30, 0x32, 0x37, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x32, 0x33, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x32, 0x37, 0x2e, 0x36, 0x33, 0x31, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x6c, 0x32, 0x37, 0x2e, 0x36, 0x32, 0x33, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x34, 0x2d, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x31, 0x2e, 0x34, 0x30, 0x33, 0x2d, 0x33, 0x2e, 0x34, 0x31, 0x37, 0x63, 0x2d, 0x33, 0x2e, 0x33, 0x31, 0x32, 0x2d, 0x38, 0x2e, 0x30, 0x35, 0x2d, 0x34, 0x2e, 0x32, 0x38, 0x34, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x33, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x38, 0x33, 0x20, 0x31, 0x32, 0x2e, 0x36, 0x37, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x32, 0x34, 0x2e, 0x39, 0x35, 0x34, 0x2d, 0x34, 0x2e, 0x39, 0x32, 0x20, 0x33, 0x36, 0x2e, 0x37, 0x33, 0x38, 0x2d, 0x39, 0x2e, 0x30, 0x34, 0x35, 0x61, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x38, 0x32, 0x2d, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x36, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x38, 0x34, 0x38, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x36, 0x6c, 0x32, 0x2e, 0x38, 0x30, 0x39, 0x20, 0x32, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x2e, 0x38, 0x36, 0x32, 0x2d, 0x33, 0x2e, 0x31, 0x36, 0x38, 0x63, 0x39, 0x2e, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x32, 0x39, 0x37, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x36, 0x38, 0x2d, 0x33, 0x33, 0x2e, 0x39, 0x36, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x34, 0x32, 0x2d, 0x35, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x31, 0x34, 0x2e, 0x32, 0x37, 0x39, 0x7a, 0x4d, 0x31, 0x36, 0x37, 0x2e, 0x34, 0x39, 0x20, 0x31, 0x37, 0x32, 0x2e, 0x39, 0x36, 0x63, 0x2d, 0x31, 0x33, 0x2e, 0x30, 0x36, 0x38, 0x20, 0x33, 0x2e, 0x35, 0x35, 0x34, 0x2d, 0x32, 0x36, 0x2e, 0x33, 0x34, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x33, 0x32, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x31, 0x33, 0x2e, 0x32, 0x32, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x36, 0x2e, 0x34, 0x38, 0x33, 0x2d, 0x31, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x36, 0x33, 0x2d, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x61, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x33, 0x32, 0x2d, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x63, 0x2d, 0x34, 0x2e, 0x30, 0x36, 0x36, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x31, 0x37, 0x2d, 0x36, 0x2e, 0x34, 0x34, 0x35, 0x2d, 0x32, 0x35, 0x2e, 0x36, 0x33, 0x2d, 0x37, 0x2e, 0x31, 0x33, 0x35, 0x2d, 0x33, 0x39, 0x2e, 0x31, 0x33, 0x34, 0x20, 0x38, 0x2e, 0x34, 0x34, 0x36, 0x2d, 0x31, 0x30, 0x2e, 0x34, 0x34, 0x33, 0x20, 0x31, 0x38, 0x2e, 0x30, 0x35, 0x32, 0x2d, 0x31, 0x39, 0x2e, 0x35, 0x39, 0x31, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x32, 0x37, 0x2e, 0x32, 0x39, 0x33, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x39, 0x36, 0x35, 0x2d, 0x31, 0x39, 0x2e, 0x30, 0x31, 0x31, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x38, 0x39, 0x38, 0x20, 0x31, 0x38, 0x2e, 0x39, 0x37, 0x63, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x34, 0x20, 0x37, 0x2e, 0x37, 0x34, 0x33, 0x20, 0x32, 0x30, 0x2e, 0x33, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x39, 0x36, 0x32, 0x20, 0x32, 0x38, 0x2e, 0x37, 0x39, 0x20, 0x32, 0x37, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x37, 0x32, 0x34, 0x20, 0x31, 0x33, 0x2e, 0x34, 0x32, 0x37, 0x2d, 0x33, 0x2e, 0x31, 0x33, 0x32, 0x20, 0x32, 0x36, 0x2e, 0x34, 0x36, 0x35, 0x2d, 0x37, 0x2e, 0x32, 0x30, 0x34, 0x20, 0x33, 0x38, 0x2e, 0x39, 0x36, 0x31, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x35, 0x32, 0x20, 0x33, 0x35, 0x2e, 0x37, 0x30, 0x37, 0x7a, 0x6d, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x32, 0x2e, 0x39, 0x39, 0x38, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x20, 0x37, 0x2e, 0x34, 0x38, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x39, 0x2e, 0x32, 0x31, 0x37, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x36, 0x2d, 0x37, 0x2e, 0x34, 0x37, 0x33, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x7a, 0x6d, 0x2d, 0x32, 0x31, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x30, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x2d, 0x37, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x33, 0x20, 0x37, 0x2e, 0x34, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x34, 0x31, 0x39, 0x45, 0x44, 0x41, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e, 0xa}, MediaType: "image/svg+xml"}, Description: "A message about etcd operator, a description of channels"}, {Schema: "olm.package", Name: "", DefaultChannel: "", Icon: nil, Description: ""}, }, Bundles: []Bundle{ diff --git a/alpha/declcfg/model_to_declcfg.go b/alpha/declcfg/model_to_declcfg.go index fabb0d0d2..0b73284c7 100644 --- a/alpha/declcfg/model_to_declcfg.go +++ b/alpha/declcfg/model_to_declcfg.go @@ -12,9 +12,9 @@ func ConvertFromModel(mpkgs model.Model) DeclarativeConfig { for _, mpkg := range mpkgs { channels, bundles := traverseModelChannels(*mpkg) - var i *Icon + var i *PackageIcon if mpkg.Icon != nil { - i = &Icon{ + i = &PackageIcon{ Data: mpkg.Icon.Data, MediaType: mpkg.Icon.MediaType, } diff --git a/alpha/declcfg/write.go b/alpha/declcfg/write.go index 293d9363b..e986a6038 100644 --- a/alpha/declcfg/write.go +++ b/alpha/declcfg/write.go @@ -405,6 +405,12 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error { pkgNames.Insert(pkgName) packagesByName[pkgName] = append(packagesByName[pkgName], p) } + iconsByPackage := map[string][]Icon{} + for _, i := range cfg.Icons { + pkgName := i.Package + pkgNames.Insert(pkgName) + iconsByPackage[pkgName] = append(iconsByPackage[pkgName], i) + } channelsByPackage := map[string][]Channel{} for _, c := range cfg.Channels { pkgName := c.Package @@ -441,6 +447,13 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error { } } + icons := iconsByPackage[pName] + for _, i := range icons { + if err := enc.Encode(i); err != nil { + return err + } + } + channels := channelsByPackage[pName] sort.Slice(channels, func(i, j int) bool { return channels[i].Name < channels[j].Name @@ -501,6 +514,10 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error { type WriteFunc func(config DeclarativeConfig, w io.Writer) error func WriteFS(cfg DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt string) error { + iconsByPackage := map[string][]Icon{} + for _, i := range cfg.Icons { + iconsByPackage[i.Package] = append(iconsByPackage[i.Package], i) + } channelsByPackage := map[string][]Channel{} for _, c := range cfg.Channels { channelsByPackage[c.Package] = append(channelsByPackage[c.Package], c) @@ -509,6 +526,14 @@ func WriteFS(cfg DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt for _, b := range cfg.Bundles { bundlesByPackage[b.Package] = append(bundlesByPackage[b.Package], b) } + deprecationsByPackage := map[string][]Deprecation{} + for _, d := range cfg.Deprecations { + deprecationsByPackage[d.Package] = append(deprecationsByPackage[d.Package], d) + } + othersByPackage := map[string][]Meta{} + for _, o := range cfg.Others { + othersByPackage[o.Package] = append(othersByPackage[o.Package], o) + } if err := os.MkdirAll(rootDir, 0777); err != nil { return err @@ -516,9 +541,12 @@ func WriteFS(cfg DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt for _, p := range cfg.Packages { fcfg := DeclarativeConfig{ - Packages: []Package{p}, - Channels: channelsByPackage[p.Name], - Bundles: bundlesByPackage[p.Name], + Packages: []Package{p}, + Icons: iconsByPackage[p.Name], + Channels: channelsByPackage[p.Name], + Bundles: bundlesByPackage[p.Name], + Deprecations: deprecationsByPackage[p.Name], + Others: othersByPackage[p.Name], } pkgDir := filepath.Join(rootDir, p.Name) if err := os.MkdirAll(pkgDir, 0777); err != nil { diff --git a/alpha/model/model.go b/alpha/model/model.go index 9b4e3ae85..966b3c774 100644 --- a/alpha/model/model.go +++ b/alpha/model/model.go @@ -14,6 +14,8 @@ import ( "golang.org/x/exp/maps" "k8s.io/apimachinery/pkg/util/sets" + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-registry/alpha/property" ) @@ -50,6 +52,13 @@ type Package struct { DefaultChannel *Channel Channels map[string]*Channel Deprecation *Deprecation + + DisplayName string + ShortDescription string + Provider *v1alpha1.AppLink + Maintainers []v1alpha1.Maintainer + Links []v1alpha1.AppLink + Keywords []string } func (m *Package) Validate() error { @@ -59,6 +68,27 @@ func (m *Package) Validate() error { result.subErrors = append(result.subErrors, errors.New("package name must not be empty")) } + const maxShortDescriptionLength = 256 + if len(m.ShortDescription) > maxShortDescriptionLength { + result.subErrors = append(result.subErrors, fmt.Errorf("short description must not be more than %d characters, found %d characters", maxShortDescriptionLength, len(m.ShortDescription))) + } + + for i, maintainer := range m.Maintainers { + if maintainer.Name == "" && maintainer.Email == "" { + result.subErrors = append(result.subErrors, fmt.Errorf("maintainer at index %d must not be empty", i)) + } + } + for i, link := range m.Links { + if link.Name == "" && link.URL == "" { + result.subErrors = append(result.subErrors, fmt.Errorf("link at index %d must not be empty", i)) + } + } + for i, keyword := range m.Keywords { + if keyword == "" { + result.subErrors = append(result.subErrors, fmt.Errorf("keyword at index %d must not be empty", i)) + } + } + if err := m.Icon.Validate(); err != nil { result.subErrors = append(result.subErrors, err) } @@ -310,6 +340,7 @@ type Bundle struct { Package *Package Channel *Channel Name string + Version semver.Version Image string Replaces string Skips []string @@ -326,7 +357,6 @@ type Bundle struct { // These fields are used to compare bundles in a diff. PropertiesP *property.Properties - Version semver.Version } func (b *Bundle) Validate() error { @@ -363,8 +393,20 @@ func (b *Bundle) Validate() error { // } //} - if props != nil && len(props.Packages) != 1 { - result.subErrors = append(result.subErrors, fmt.Errorf("must be exactly one property with type %q", property.TypePackage)) + if b.Version.String() == "0.0.0" { + result.subErrors = append(result.subErrors, errors.New("version must be set")) + } + + if props != nil { + if len(props.Packages) > 1 { + result.subErrors = append(result.subErrors, errors.New("no more than one olm.package property can be defined")) + } + if len(props.Packages) == 1 { + pkgProp := props.Packages[0] + if pkgProp.PackageName != b.Package.Name || pkgProp.Version != b.Version.String() { + result.subErrors = append(result.subErrors, errors.New("olm.package property does not match bundle's package name and version")) + } + } } if b.Image == "" && len(b.Objects) == 0 { diff --git a/alpha/model/model_test.go b/alpha/model/model_test.go index 11391b74c..61a0d283f 100644 --- a/alpha/model/model_test.go +++ b/alpha/model/model_test.go @@ -466,6 +466,7 @@ func TestValidators(t *testing.T) { Package: pkg, Channel: ch, Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), Image: "registry.io/image", Replaces: "anakin.v0.0.1", Skips: []string{"anakin.v0.0.2"}, @@ -476,12 +477,29 @@ func TestValidators(t *testing.T) { }, assertion: require.NoError, }, + { + name: "Bundle/Success/NoPackageProperty", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), + Image: "registry.io/image", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{ + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + }, + }, + assertion: require.NoError, + }, { name: "Bundle/Success/ReplacesNotInChannel", v: &Bundle{ Package: pkg, Channel: ch, Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), Image: "registry.io/image", Replaces: "anakin.v0.0.0", Properties: []property.Property{ @@ -496,6 +514,7 @@ func TestValidators(t *testing.T) { Package: pkg, Channel: ch, Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), Image: "", Properties: []property.Property{ property.MustBuildPackage("anakin", "0.1.0"), @@ -513,6 +532,7 @@ func TestValidators(t *testing.T) { Package: pkg, Channel: ch, Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), Image: "", Properties: []property.Property{ property.MustBuildPackage("anakin", "0.1.0"), @@ -574,17 +594,48 @@ func TestValidators(t *testing.T) { assertion: hasError(`skip[0] is empty`), }, { - name: "Bundle/Error/MissingPackage", + name: "Bundle/Error/MissingVersion", v: &Bundle{ - Package: pkg, - Channel: ch, - Name: "anakin.v0.1.0", - Image: "", - Replaces: "anakin.v0.0.1", - Skips: []string{"anakin.v0.0.2"}, - Properties: []property.Property{}, + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + }, + assertion: hasError(`version must be set`), + }, + { + name: "Bundle/Error/PackagePropertyMismatchedPackageName", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), + Image: "", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{ + property.MustBuildPackage("vader", "0.1.0"), + }, + }, + assertion: hasError(`olm.package property does not match bundle's package name and version`), + }, + { + name: "Bundle/Error/PackagePropertyMismatchedVersion", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), + Image: "", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.2.0"), + }, }, - assertion: hasError(`must be exactly one property with type "olm.package"`), + assertion: hasError(`olm.package property does not match bundle's package name and version`), }, { name: "Bundle/Error/MultiplePackages", @@ -592,6 +643,7 @@ func TestValidators(t *testing.T) { Package: pkg, Channel: ch, Name: "anakin.v0.1.0", + Version: semver.MustParse("0.1.0"), Image: "", Replaces: "anakin.v0.0.1", Skips: []string{"anakin.v0.0.2"}, @@ -600,7 +652,7 @@ func TestValidators(t *testing.T) { property.MustBuildPackage("anakin", "0.2.0"), }, }, - assertion: hasError(`must be exactly one property with type "olm.package"`), + assertion: hasError(`no more than one olm.package property can be defined`), }, { name: "RelatedImage/Success/Valid", diff --git a/go.mod b/go.mod index 82314b45c..aad2a2d22 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.3 toolchain go1.23.6 require ( + github.com/Masterminds/semver/v3 v3.3.1 github.com/akrylysov/pogreb v0.10.2 github.com/blang/semver/v4 v4.0.0 github.com/containerd/containerd v1.7.27 diff --git a/go.sum b/go.sum index 0598e350d..0dc92482c 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg= diff --git a/pkg/api/model_to_api.go b/pkg/api/model_to_api.go index b3368383f..137086c02 100644 --- a/pkg/api/model_to_api.go +++ b/pkg/api/model_to_api.go @@ -23,26 +23,7 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { csvJSON := b.CsvJSON if csvJSON == "" && len(props.CSVMetadatas) == 1 { - var icons []v1alpha1.Icon - if b.Package.Icon != nil { - icons = []v1alpha1.Icon{{ - Data: base64.StdEncoding.EncodeToString(b.Package.Icon.Data), - MediaType: b.Package.Icon.MediaType, - }} - } - csv := csvMetadataToCsv(props.CSVMetadatas[0]) - csv.Name = b.Name - csv.Spec.Icon = icons - csv.Spec.InstallStrategy = v1alpha1.NamedInstallStrategy{ - // This stub is required to avoid a panic in OLM's package server that results in - // attemptint to write to a nil map. - StrategyName: "deployment", - } - csv.Spec.Version = version.OperatorVersion{Version: b.Version} - csv.Spec.RelatedImages = convertModelRelatedImagesToCSVRelatedImages(b.RelatedImages) - if csv.Spec.Description == "" { - csv.Spec.Description = b.Package.Description - } + csv := newSyntheticCSV(b) csvData, err := json.Marshal(csv) if err != nil { return nil, err @@ -64,6 +45,11 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { if err != nil { return nil, fmt.Errorf("convert model properties to api dependencies: %v", err) } + + properties := b.Properties + if len(props.Packages) == 0 { + properties = append(properties, property.MustBuildPackage(b.Package.Name, b.Version.String())) + } return &Bundle{ CsvName: b.Name, PackageName: b.Package.Name, @@ -71,10 +57,10 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) { BundlePath: b.Image, ProvidedApis: gvksProvidedtoAPIGVKs(props.GVKs), RequiredApis: gvksRequirestoAPIGVKs(props.GVKsRequired), - Version: props.Packages[0].Version, + Version: b.Version.String(), SkipRange: b.SkipRange, Dependencies: apiDeps, - Properties: convertModelPropertiesToAPIProperties(b.Properties), + Properties: convertModelPropertiesToAPIProperties(properties), Replaces: b.Replaces, Skips: b.Skips, CsvJson: csvJSON, @@ -89,10 +75,6 @@ func parseProperties(in []property.Property) (*property.Properties, error) { return nil, err } - if len(props.Packages) != 1 { - return nil, fmt.Errorf("expected exactly 1 property of type %q, found %d", property.TypePackage, len(props.Packages)) - } - if len(props.CSVMetadatas) > 1 { return nil, fmt.Errorf("expected at most 1 property of type %q, found %d", property.TypeCSVMetadata, len(props.CSVMetadatas)) } @@ -100,29 +82,74 @@ func parseProperties(in []property.Property) (*property.Properties, error) { return props, nil } -func csvMetadataToCsv(m property.CSVMetadata) v1alpha1.ClusterServiceVersion { +func newSyntheticCSV(b model.Bundle) v1alpha1.ClusterServiceVersion { + pkg := b.Package + csvMetadata := b.PropertiesP.CSVMetadatas[0] + + var icons []v1alpha1.Icon + if pkg.Icon != nil { + icons = []v1alpha1.Icon{{ + Data: base64.StdEncoding.EncodeToString(pkg.Icon.Data), + MediaType: pkg.Icon.MediaType, + }} + } + + // Copy package-level metadata into CSV if fields are unset in CSV + if csvMetadata.DisplayName == "" { + csvMetadata.DisplayName = pkg.DisplayName + } + if _, ok := csvMetadata.Annotations["description"]; !ok { + csvMetadata.Annotations["description"] = pkg.ShortDescription + } + if csvMetadata.Description == "" { + csvMetadata.Description = pkg.Description + } + if csvMetadata.Provider.Name == "" && csvMetadata.Provider.URL == "" && pkg.Provider != nil { + csvMetadata.Provider = *pkg.Provider + } + if csvMetadata.Maintainers == nil { + csvMetadata.Maintainers = pkg.Maintainers + } + if csvMetadata.Links == nil { + csvMetadata.Links = pkg.Links + } + if csvMetadata.Keywords == nil { + csvMetadata.Keywords = pkg.Keywords + } + + // Return syntheticly generated CSV return v1alpha1.ClusterServiceVersion{ TypeMeta: metav1.TypeMeta{ Kind: operators.ClusterServiceVersionKind, APIVersion: v1alpha1.ClusterServiceVersionAPIVersion, }, ObjectMeta: metav1.ObjectMeta{ - Annotations: m.Annotations, - Labels: m.Labels, + Name: b.Name, + Annotations: csvMetadata.Annotations, + Labels: csvMetadata.Labels, }, Spec: v1alpha1.ClusterServiceVersionSpec{ - APIServiceDefinitions: m.APIServiceDefinitions, - CustomResourceDefinitions: m.CustomResourceDefinitions, - Description: m.Description, - DisplayName: m.DisplayName, - InstallModes: m.InstallModes, - Keywords: m.Keywords, - Links: m.Links, - Maintainers: m.Maintainers, - Maturity: m.Maturity, - MinKubeVersion: m.MinKubeVersion, - NativeAPIs: m.NativeAPIs, - Provider: m.Provider, + APIServiceDefinitions: csvMetadata.APIServiceDefinitions, + CustomResourceDefinitions: csvMetadata.CustomResourceDefinitions, + Description: csvMetadata.Description, + DisplayName: csvMetadata.DisplayName, + InstallModes: csvMetadata.InstallModes, + Keywords: csvMetadata.Keywords, + Links: csvMetadata.Links, + Maintainers: csvMetadata.Maintainers, + Maturity: csvMetadata.Maturity, + MinKubeVersion: csvMetadata.MinKubeVersion, + NativeAPIs: csvMetadata.NativeAPIs, + Provider: csvMetadata.Provider, + + Icon: icons, + InstallStrategy: v1alpha1.NamedInstallStrategy{ + // This stub is required to avoid a panic in OLM's package server that results in + // attemptint to write to a nil map. + StrategyName: "deployment", + }, + Version: version.OperatorVersion{Version: b.Version}, + RelatedImages: convertModelRelatedImagesToCSVRelatedImages(b.RelatedImages), }, } }