Skip to content

Commit e53ddd1

Browse files
committed
add support for handling multiple bundle types
Signed-off-by: Bryce Palmer <[email protected]>
1 parent b982ad0 commit e53ddd1

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

internal/controllers/operator_controller.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,19 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
152152
op.Status.ResolvedBundleResource = bundleImage
153153
setResolvedStatusConditionSuccess(&op.Status.Conditions, fmt.Sprintf("resolved to %q", bundleImage), op.GetGeneration())
154154

155+
mediaType, err := bundleEntity.MediaType()
156+
if err != nil {
157+
setInstalledStatusConditionFailed(&op.Status.Conditions, err.Error(), op.GetGeneration())
158+
return ctrl.Result{}, err
159+
}
160+
bundleProvisioner, err := mapBundleMediaTypeToBundleProvisioner(mediaType)
161+
if err != nil {
162+
setInstalledStatusConditionFailed(&op.Status.Conditions, err.Error(), op.GetGeneration())
163+
return ctrl.Result{}, err
164+
}
155165
// Ensure a BundleDeployment exists with its bundle source from the bundle
156166
// image we just looked up in the solution.
157-
dep := r.generateExpectedBundleDeployment(*op, bundleImage)
167+
dep := r.generateExpectedBundleDeployment(*op, bundleImage, bundleProvisioner)
158168
if err := r.ensureBundleDeployment(ctx, dep); err != nil {
159169
// originally Reason: operatorsv1alpha1.ReasonInstallationFailed
160170
op.Status.InstalledBundleResource = ""
@@ -240,12 +250,13 @@ func (r *OperatorReconciler) getBundleEntityFromSolution(solution *solver.Soluti
240250
return nil, fmt.Errorf("entity for package %q not found in solution", packageName)
241251
}
242252

243-
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string) *unstructured.Unstructured {
253+
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string) *unstructured.Unstructured {
244254
// We use unstructured here to avoid problems of serializing default values when sending patches to the apiserver.
245255
// If you use a typed object, any default values from that struct get serialized into the JSON patch, which could
246256
// cause unrelated fields to be patched back to the default value even though that isn't the intention. Using an
247257
// unstructured ensures that the patch contains only what is specified. Using unstructured like this is basically
248258
// identical to "kubectl apply -f"
259+
249260
bd := &unstructured.Unstructured{Object: map[string]interface{}{
250261
"apiVersion": rukpakv1alpha1.GroupVersion.String(),
251262
"kind": rukpakv1alpha1.BundleDeploymentKind,
@@ -257,8 +268,7 @@ func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha
257268
"provisionerClassName": "core-rukpak-io-plain",
258269
"template": map[string]interface{}{
259270
"spec": map[string]interface{}{
260-
// TODO: Don't assume registry provisioner
261-
"provisionerClassName": "core-rukpak-io-registry",
271+
"provisionerClassName": bundleProvisioner,
262272
"source": map[string]interface{}{
263273
// TODO: Don't assume image type
264274
"type": string(rukpakv1alpha1.SourceTypeImage),
@@ -357,6 +367,19 @@ func isBundleDepStale(bd *rukpakv1alpha1.BundleDeployment) bool {
357367
return bd != nil && bd.Status.ObservedGeneration != bd.GetGeneration()
358368
}
359369

370+
// mapBundleMediaTypeToBundleProvisioner maps an olm.bundle.mediatype property to a
371+
// rukpak bundle provisioner class name that is capable of unpacking the bundle type
372+
func mapBundleMediaTypeToBundleProvisioner(mediaType string) (string, error) {
373+
switch mediaType {
374+
case entity.MediaTypePlain:
375+
return "core-rukpak-io-plain", nil
376+
case entity.MediaTypeRegistry, "":
377+
return "core-rukpak-io-registry", nil
378+
default:
379+
return "", fmt.Errorf("unknown bundle mediatype: %s", mediaType)
380+
}
381+
}
382+
360383
// setResolvedStatusConditionSuccess sets the resolved status condition to success.
361384
func setResolvedStatusConditionSuccess(conditions *[]metav1.Condition, message string, generation int64) {
362385
apimeta.SetStatusCondition(conditions, metav1.Condition{

internal/resolution/variable_sources/entity/bundle_entity.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import (
1111
)
1212

1313
const PropertyBundlePath = "olm.bundle.path"
14+
const PropertyBundleMediaType = "olm.bundle.mediatype"
15+
16+
type MediaType string
17+
18+
const (
19+
MediaTypePlain = "plain+v0"
20+
MediaTypeRegistry = "registry+v1"
21+
)
1422

1523
type ChannelProperties struct {
1624
property.Channel
@@ -58,6 +66,7 @@ type BundleEntity struct {
5866
channelProperties *ChannelProperties
5967
semVersion *semver.Version
6068
bundlePath string
69+
mediaType string
6170
mu sync.RWMutex
6271
}
6372

@@ -124,6 +133,27 @@ func (b *BundleEntity) BundlePath() (string, error) {
124133
return b.bundlePath, nil
125134
}
126135

136+
func (b *BundleEntity) MediaType() (string, error) {
137+
if err := b.loadMediaType(); err != nil {
138+
return "", err
139+
}
140+
141+
return b.mediaType, nil
142+
}
143+
144+
func (b *BundleEntity) loadMediaType() error {
145+
b.mu.Lock()
146+
defer b.mu.Unlock()
147+
if b.mediaType == "" {
148+
mediaType, err := loadFromEntity[string](b.Entity, PropertyBundleMediaType, optional)
149+
if err != nil {
150+
return fmt.Errorf("error determining bundle mediatype for entity '%s': %w", b.ID, err)
151+
}
152+
b.mediaType = mediaType
153+
}
154+
return nil
155+
}
156+
127157
func (b *BundleEntity) loadPackage() error {
128158
b.mu.Lock()
129159
defer b.mu.Unlock()

internal/resolution/variable_sources/entity/bundle_entity_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package entity_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/blang/semver/v4"
@@ -267,4 +268,32 @@ var _ = Describe("BundleEntity", func() {
267268
Expect(err.Error()).To(Equal("error determining bundle path for entity 'operatorhub/prometheus/0.14.0': property 'olm.bundle.path' ('badBundlePath') could not be parsed: invalid character 'b' looking for beginning of value"))
268269
})
269270
})
271+
272+
Describe("MediaType", func() {
273+
It("should return the bundle mediatype property if present", func() {
274+
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{
275+
olmentity.PropertyBundleMediaType: fmt.Sprintf(`"%s"`, olmentity.MediaTypePlain),
276+
})
277+
bundleEntity := olmentity.NewBundleEntity(entity)
278+
mediaType, err := bundleEntity.MediaType()
279+
Expect(err).ToNot(HaveOccurred())
280+
Expect(mediaType).To(Equal(olmentity.MediaTypePlain))
281+
})
282+
It("should not return an error if the property is not found", func() {
283+
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{})
284+
bundleEntity := olmentity.NewBundleEntity(entity)
285+
mediaType, err := bundleEntity.MediaType()
286+
Expect(mediaType).To(BeEmpty())
287+
Expect(err).To(BeNil())
288+
})
289+
It("should return error if the property is malformed", func() {
290+
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{
291+
olmentity.PropertyBundleMediaType: "badtype",
292+
})
293+
bundleEntity := olmentity.NewBundleEntity(entity)
294+
mediaType, err := bundleEntity.MediaType()
295+
Expect(mediaType).To(BeEmpty())
296+
Expect(err.Error()).To(Equal("error determining bundle mediatype for entity 'operatorhub/prometheus/0.14.0': property 'olm.bundle.mediatype' ('badtype') could not be parsed: invalid character 'b' looking for beginning of value"))
297+
})
298+
})
270299
})

0 commit comments

Comments
 (0)