Skip to content

Commit

Permalink
attempt to publish FBC read/write
Browse files Browse the repository at this point in the history
Signed-off-by: Jordan Keister <[email protected]>
  • Loading branch information
grokspawn committed Oct 5, 2022
1 parent 8c8babd commit a151be5
Show file tree
Hide file tree
Showing 21 changed files with 5,425 additions and 20 deletions.
31 changes: 21 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/operator-framework/api
module github.com/grokspawn/api

go 1.18

Expand All @@ -8,18 +8,25 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/go-bindata/go-bindata/v3 v3.1.3
github.com/google/cel-go v0.10.1
github.com/google/go-cmp v0.5.6 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
github.com/stretchr/testify v1.7.0
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac
k8s.io/api v0.24.0
k8s.io/apiextensions-apiserver v0.24.0
k8s.io/apimachinery v0.24.0
k8s.io/client-go v0.24.0
sigs.k8s.io/controller-runtime v0.12.1
)

require (
github.com/h2non/filetype v1.1.3
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c
github.com/joelanford/ignore v0.0.0-20210610194209-63d4919d8fb2
github.com/operator-framework/operator-registry v1.26.2
sigs.k8s.io/yaml v1.3.0
)

require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
Expand All @@ -29,6 +36,9 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.1.0 // indirect
github.com/go-git/go-git/v5 v5.3.0 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
Expand All @@ -38,10 +48,11 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kisielk/errcheck v1.5.0 // indirect
Expand Down Expand Up @@ -69,18 +80,19 @@ require (
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/grpc v1.40.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/apiserver v0.24.0 // indirect
Expand All @@ -91,5 +103,4 @@ require (
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
73 changes: 63 additions & 10 deletions go.sum

Large diffs are not rendered by default.

109 changes: 109 additions & 0 deletions pkg/lib/declcfg/declcfg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package declcfg

import (
"encoding/json"

"github.com/operator-framework/operator-registry/alpha/property"
)

const (
SchemaPackage = "olm.package"
SchemaChannel = "olm.channel"
SchemaBundle = "olm.bundle"
)

type DeclarativeConfig struct {
Packages []Package
Channels []Channel
Bundles []Bundle
Others []Meta
}

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"`
}

type Icon struct {
Data []byte `json:"base64data"`
MediaType string `json:"mediatype"`
}

type Channel struct {
Schema string `json:"schema"`
Name string `json:"name"`
Package string `json:"package"`
Entries []ChannelEntry `json:"entries"`
Properties []property.Property `json:"properties,omitempty" hash:"set"`
}

type ChannelEntry struct {
Name string `json:"name"`
Replaces string `json:"replaces,omitempty"`
Skips []string `json:"skips,omitempty"`
SkipRange string `json:"skipRange,omitempty"`
}

// Bundle specifies all metadata and data of a bundle object.
// Top-level fields are the source of truth, i.e. not CSV values.
//
// Notes:
// - Any field slice type field or type containing a slice somewhere
// where two types/fields are equal if their contents are equal regardless
// of order must have a `hash:"set"` field tag for bundle comparison.
// - Any fields that have a `json:"-"` tag must be included in the equality
// evaluation in bundlesEqual().
type Bundle struct {
Schema string `json:"schema"`
Name string `json:"name"`
Package string `json:"package"`
Image string `json:"image"`
Properties []property.Property `json:"properties,omitempty" hash:"set"`
RelatedImages []RelatedImage `json:"relatedImages,omitempty" hash:"set"`

// These fields are present so that we can continue serving
// the GRPC API the way packageserver expects us to in a
// backwards-compatible way. These are populated from
// any `olm.bundle.object` properties.
//
// These fields will never be persisted in the bundle blob as
// first class fields.
CsvJSON string `json:"-"`
Objects []string `json:"-"`
}

type RelatedImage struct {
Name string `json:"name"`
Image string `json:"image"`
}

type Meta struct {
Schema string
Package string

Blob json.RawMessage
}

func (m Meta) MarshalJSON() ([]byte, error) {
return m.Blob, nil
}

func (m *Meta) UnmarshalJSON(blob []byte) error {
type tmp struct {
Schema string `json:"schema"`
Package string `json:"package,omitempty"`
Properties []property.Property `json:"properties,omitempty"`
}
var t tmp
if err := json.Unmarshal(blob, &t); err != nil {
return err
}
m.Schema = t.Schema
m.Package = t.Package
m.Blob = blob
return nil
}
187 changes: 187 additions & 0 deletions pkg/lib/declcfg/declcfg_to_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package declcfg

import (
"fmt"

"github.com/blang/semver/v4"
"k8s.io/apimachinery/pkg/util/sets"

"github.com/operator-framework/operator-registry/alpha/model"
"github.com/operator-framework/operator-registry/alpha/property"
)

func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
mpkgs := model.Model{}
defaultChannels := map[string]string{}
for _, p := range cfg.Packages {
if p.Name == "" {
return nil, fmt.Errorf("config contains package with no name")
}

if _, ok := mpkgs[p.Name]; ok {
return nil, fmt.Errorf("duplicate package %q", p.Name)
}

mpkg := &model.Package{
Name: p.Name,
Description: p.Description,
Channels: map[string]*model.Channel{},
}
if p.Icon != nil {
mpkg.Icon = &model.Icon{
Data: p.Icon.Data,
MediaType: p.Icon.MediaType,
}
}
defaultChannels[p.Name] = p.DefaultChannel
mpkgs[p.Name] = mpkg
}

channelDefinedEntries := map[string]sets.String{}
for _, c := range cfg.Channels {
mpkg, ok := mpkgs[c.Package]
if !ok {
return nil, fmt.Errorf("unknown package %q for channel %q", c.Package, c.Name)
}

if c.Name == "" {
return nil, fmt.Errorf("package %q contains channel with no name", c.Package)
}

if _, ok := mpkg.Channels[c.Name]; ok {
return nil, fmt.Errorf("package %q has duplicate channel %q", c.Package, c.Name)
}

mch := &model.Channel{
Package: mpkg,
Name: c.Name,
Bundles: map[string]*model.Bundle{},
// NOTICE: The field Properties of the type Channel is for internal use only.
// DO NOT use it for any public-facing functionalities.
// This API is in alpha stage and it is subject to change.
Properties: c.Properties,
}

cde := sets.NewString()
for _, entry := range c.Entries {
if _, ok := mch.Bundles[entry.Name]; ok {
return nil, fmt.Errorf("invalid package %q, channel %q: duplicate entry %q", c.Package, c.Name, entry.Name)
}
cde = cde.Insert(entry.Name)
mch.Bundles[entry.Name] = &model.Bundle{
Package: mpkg,
Channel: mch,
Name: entry.Name,
Replaces: entry.Replaces,
Skips: entry.Skips,
SkipRange: entry.SkipRange,
}
}
channelDefinedEntries[c.Package] = cde

mpkg.Channels[c.Name] = mch

defaultChannelName := defaultChannels[c.Package]
if defaultChannelName == c.Name {
mpkg.DefaultChannel = mch
}
}

// packageBundles tracks the set of bundle names for each package
// and is used to detect duplicate bundles.
packageBundles := map[string]sets.String{}

for _, b := range cfg.Bundles {
if b.Package == "" {
return nil, fmt.Errorf("package name must be set for bundle %q", b.Name)
}
mpkg, ok := mpkgs[b.Package]
if !ok {
return nil, fmt.Errorf("unknown package %q for bundle %q", b.Package, b.Name)
}

bundles, ok := packageBundles[b.Package]
if !ok {
bundles = sets.NewString()
}
if bundles.Has(b.Name) {
return nil, fmt.Errorf("package %q has duplicate bundle %q", b.Package, b.Name)
}
bundles.Insert(b.Name)
packageBundles[b.Package] = bundles

props, err := property.Parse(b.Properties)
if err != nil {
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)
}

// 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)
}

channelDefinedEntries[b.Package] = channelDefinedEntries[b.Package].Delete(b.Name)
found := false
for _, mch := range mpkg.Channels {
if mb, ok := mch.Bundles[b.Name]; ok {
found = true
mb.Image = b.Image
mb.Properties = b.Properties
mb.RelatedImages = relatedImagesToModelRelatedImages(b.RelatedImages)
mb.CsvJSON = b.CsvJSON
mb.Objects = b.Objects
mb.PropertiesP = props
mb.Version = ver
}
}
if !found {
return nil, fmt.Errorf("package %q, bundle %q not found in any channel entries", b.Package, b.Name)
}
}

for pkg, entries := range channelDefinedEntries {
if entries.Len() > 0 {
return nil, fmt.Errorf("no olm.bundle blobs found in package %q for olm.channel entries %s", pkg, entries.List())
}
}

for _, mpkg := range mpkgs {
defaultChannelName := defaultChannels[mpkg.Name]
if defaultChannelName != "" && mpkg.DefaultChannel == nil {
dch := &model.Channel{
Package: mpkg,
Name: defaultChannelName,
Bundles: map[string]*model.Bundle{},
}
mpkg.DefaultChannel = dch
mpkg.Channels[dch.Name] = dch
}
}

if err := mpkgs.Validate(); err != nil {
return nil, err
}
mpkgs.Normalize()
return mpkgs, nil
}

func relatedImagesToModelRelatedImages(in []RelatedImage) []model.RelatedImage {
var out []model.RelatedImage
for _, p := range in {
out = append(out, model.RelatedImage{
Name: p.Name,
Image: p.Image,
})
}
return out
}
Loading

0 comments on commit a151be5

Please sign in to comment.