Skip to content

Commit fffa59b

Browse files
authored
[resolution pt.1] bundle entity (#95)
* update vendor * add bundle entity * add entity source predicates * add entity sort functions Signed-off-by: perdasilva <[email protected]>
1 parent d1b2189 commit fffa59b

File tree

8 files changed

+861
-5
lines changed

8 files changed

+861
-5
lines changed

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ module github.com/operator-framework/operator-controller
33
go 1.19
44

55
require (
6+
github.com/blang/semver/v4 v4.0.0
67
github.com/onsi/ginkgo/v2 v2.3.1
78
github.com/onsi/gomega v1.22.1
89
github.com/operator-framework/deppy v0.0.0-20230102161649-36fa82370999
10+
github.com/operator-framework/operator-registry v1.26.2
911
k8s.io/apimachinery v0.25.0
1012
k8s.io/client-go v0.25.0
1113
sigs.k8s.io/controller-runtime v0.13.1
@@ -40,7 +42,7 @@ require (
4042
github.com/google/gnostic v0.5.7-v3refs // indirect
4143
github.com/google/go-cmp v0.5.8 // indirect
4244
github.com/google/gofuzz v1.1.0 // indirect
43-
github.com/google/uuid v1.1.2 // indirect
45+
github.com/google/uuid v1.2.0 // indirect
4446
github.com/imdario/mergo v0.3.12 // indirect
4547
github.com/josharian/intern v1.0.0 // indirect
4648
github.com/json-iterator/go v1.1.12 // indirect
@@ -58,7 +60,7 @@ require (
5860
go.uber.org/atomic v1.7.0 // indirect
5961
go.uber.org/multierr v1.6.0 // indirect
6062
go.uber.org/zap v1.21.0 // indirect
61-
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
63+
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
6264
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
6365
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
6466
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect

go.sum

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
7979
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
8080
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
8181
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
82+
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
83+
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
8284
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
8385
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
8486
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -221,8 +223,9 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
221223
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
222224
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
223225
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
224-
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
225226
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
227+
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
228+
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
226229
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
227230
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
228231
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@@ -285,6 +288,8 @@ github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
285288
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
286289
github.com/operator-framework/deppy v0.0.0-20230102161649-36fa82370999 h1:3R+Bg57vgekyDqS0w9c7vHNsHck/bo6dkaby6U9wi/8=
287290
github.com/operator-framework/deppy v0.0.0-20230102161649-36fa82370999/go.mod h1:JaF7sX6tn7mpXcOehYjSHiKM1Y0z09vEfC6dca4AVuo=
291+
github.com/operator-framework/operator-registry v1.26.2 h1:kQToR/hPqdivljaRXM0olPllNIcc/GUk1VBoGwagJmk=
292+
github.com/operator-framework/operator-registry v1.26.2/go.mod h1:Z7XIb/3ZkhBQCvMD/rJphyuY4LmU/eWpZS+o0Mm1WAk=
288293
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
289294
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
290295
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -363,8 +368,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
363368
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
364369
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
365370
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
366-
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
367-
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
371+
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
372+
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
368373
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
369374
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
370375
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package entity
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"sync"
7+
8+
"github.com/blang/semver/v4"
9+
"github.com/operator-framework/deppy/pkg/deppy/input"
10+
"github.com/operator-framework/operator-registry/alpha/property"
11+
)
12+
13+
const PropertyBundlePath = "olm.bundle.path"
14+
15+
type ChannelProperties struct {
16+
property.Channel
17+
Replaces string `json:"replaces,omitempty"`
18+
Skips []string `json:"skips,omitempty"`
19+
SkipRange string `json:"skipRange,omitempty"`
20+
}
21+
22+
type PackageRequired struct {
23+
property.PackageRequired
24+
SemverRange *semver.Range `json:"-"`
25+
}
26+
27+
type GVK property.GVK
28+
29+
func (g GVK) String() string {
30+
return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind)
31+
}
32+
33+
type GVKRequired property.GVKRequired
34+
35+
func (g GVKRequired) String() string {
36+
return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind)
37+
}
38+
39+
type BundleEntity struct {
40+
*input.Entity
41+
42+
// these properties are lazy loaded as they are requested
43+
bundlePackage *property.Package
44+
providedGVKs []GVK
45+
requiredGVKs []GVKRequired
46+
requiredPackages []PackageRequired
47+
channelProperties *ChannelProperties
48+
semVersion *semver.Version
49+
bundlePath string
50+
mu sync.RWMutex
51+
}
52+
53+
func NewBundleEntity(entity *input.Entity) *BundleEntity {
54+
return &BundleEntity{
55+
Entity: entity,
56+
mu: sync.RWMutex{},
57+
}
58+
}
59+
60+
func (b *BundleEntity) PackageName() (string, error) {
61+
if err := b.loadPackage(); err != nil {
62+
return "", err
63+
}
64+
return b.bundlePackage.PackageName, nil
65+
}
66+
67+
func (b *BundleEntity) Version() (*semver.Version, error) {
68+
if err := b.loadPackage(); err != nil {
69+
return nil, err
70+
}
71+
return b.semVersion, nil
72+
}
73+
74+
func (b *BundleEntity) ProvidedGVKs() ([]GVK, error) {
75+
if err := b.loadProvidedGVKs(); err != nil {
76+
return nil, err
77+
}
78+
return b.providedGVKs, nil
79+
}
80+
81+
func (b *BundleEntity) RequiredGVKs() ([]GVKRequired, error) {
82+
if err := b.loadRequiredGVKs(); err != nil {
83+
return nil, err
84+
}
85+
return b.requiredGVKs, nil
86+
}
87+
88+
func (b *BundleEntity) RequiredPackages() ([]PackageRequired, error) {
89+
if err := b.loadRequiredPackages(); err != nil {
90+
return nil, err
91+
}
92+
return b.requiredPackages, nil
93+
}
94+
95+
func (b *BundleEntity) ChannelName() (string, error) {
96+
if err := b.loadChannelProperties(); err != nil {
97+
return "", err
98+
}
99+
return b.channelProperties.ChannelName, nil
100+
}
101+
102+
func (b *BundleEntity) ChannelProperties() (*ChannelProperties, error) {
103+
if err := b.loadChannelProperties(); err != nil {
104+
return nil, err
105+
}
106+
return b.channelProperties, nil
107+
}
108+
109+
func (b *BundleEntity) BundlePath() (string, error) {
110+
if err := b.loadBundlePath(); err != nil {
111+
return "", err
112+
}
113+
return b.bundlePath, nil
114+
}
115+
116+
func (b *BundleEntity) loadPackage() error {
117+
b.mu.Lock()
118+
defer b.mu.Unlock()
119+
if b.bundlePackage == nil {
120+
bundlePackage, err := loadFromEntity[property.Package](b.Entity, property.TypePackage)
121+
if err != nil {
122+
return fmt.Errorf("error determining package for entity '%s': %w", b.ID, err)
123+
}
124+
b.bundlePackage = &bundlePackage
125+
if b.semVersion == nil {
126+
semVer, err := semver.Parse(b.bundlePackage.Version)
127+
if err != nil {
128+
return fmt.Errorf("could not parse semver (%s) for entity '%s': %w", b.bundlePackage.Version, b.ID, err)
129+
}
130+
b.semVersion = &semVer
131+
}
132+
}
133+
return nil
134+
}
135+
136+
func (b *BundleEntity) loadProvidedGVKs() error {
137+
b.mu.Lock()
138+
defer b.mu.Unlock()
139+
if b.providedGVKs == nil {
140+
providedGVKs, err := loadFromEntity[[]GVK](b.Entity, property.TypeGVK)
141+
if err != nil {
142+
return fmt.Errorf("error determining bundle provided gvks for entity '%s': %w", b.ID, err)
143+
}
144+
b.providedGVKs = providedGVKs
145+
}
146+
return nil
147+
}
148+
149+
func (b *BundleEntity) loadRequiredGVKs() error {
150+
b.mu.Lock()
151+
defer b.mu.Unlock()
152+
if b.requiredGVKs == nil {
153+
requiredGVKs, err := loadFromEntity[[]GVKRequired](b.Entity, property.TypeGVKRequired)
154+
if err != nil {
155+
return fmt.Errorf("error determining bundle required gvks for entity '%s': %w", b.ID, err)
156+
}
157+
b.requiredGVKs = requiredGVKs
158+
}
159+
return nil
160+
}
161+
162+
func (b *BundleEntity) loadRequiredPackages() error {
163+
b.mu.Lock()
164+
defer b.mu.Unlock()
165+
if b.requiredPackages == nil {
166+
requiredPackages, err := loadFromEntity[[]PackageRequired](b.Entity, property.TypePackageRequired)
167+
if err != nil {
168+
return fmt.Errorf("error determining bundle required packages for entity '%s': %w", b.ID, err)
169+
}
170+
for _, requiredPackage := range requiredPackages {
171+
semverRange, err := semver.ParseRange(requiredPackage.VersionRange)
172+
if err != nil {
173+
return fmt.Errorf("error determining bundle required package semver range for entity '%s': '%w'", b.ID, err)
174+
}
175+
requiredPackage.SemverRange = &semverRange
176+
}
177+
b.requiredPackages = requiredPackages
178+
}
179+
return nil
180+
}
181+
182+
func (b *BundleEntity) loadChannelProperties() error {
183+
b.mu.Lock()
184+
defer b.mu.Unlock()
185+
if b.channelProperties == nil {
186+
channel, err := loadFromEntity[ChannelProperties](b.Entity, property.TypeChannel)
187+
if err != nil {
188+
return fmt.Errorf("error determining bundle channel properties for entity '%s': %w", b.ID, err)
189+
}
190+
b.channelProperties = &channel
191+
}
192+
return nil
193+
}
194+
195+
func (b *BundleEntity) loadBundlePath() error {
196+
b.mu.Lock()
197+
defer b.mu.Unlock()
198+
if b.bundlePath == "" {
199+
bundlePath, err := loadFromEntity[string](b.Entity, PropertyBundlePath)
200+
if err != nil {
201+
return fmt.Errorf("error determining bundle path for entity '%s': %w", b.ID, err)
202+
}
203+
b.bundlePath = bundlePath
204+
}
205+
return nil
206+
}
207+
208+
func loadFromEntity[T interface{}](entity *input.Entity, propertyName string) (T, error) {
209+
deserializedProperty := *new(T)
210+
propertyValue, ok := entity.Properties[propertyName]
211+
if !ok {
212+
return deserializedProperty, fmt.Errorf("property '%s' not found", propertyName)
213+
}
214+
215+
if err := json.Unmarshal([]byte(propertyValue), &deserializedProperty); err != nil {
216+
return deserializedProperty, fmt.Errorf("property '%s' ('%s') could not be parsed: %w", propertyName, propertyValue, err)
217+
}
218+
return deserializedProperty, nil
219+
}

0 commit comments

Comments
 (0)