@@ -18,7 +18,9 @@ package controllers
18
18
19
19
import (
20
20
"context"
21
+ "fmt"
21
22
23
+ "github.com/operator-framework/deppy/pkg/deppy/solver"
22
24
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
23
25
"k8s.io/apimachinery/pkg/api/equality"
24
26
apimeta "k8s.io/apimachinery/pkg/api/meta"
@@ -35,6 +37,7 @@ import (
35
37
operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
36
38
"github.com/operator-framework/operator-controller/internal/resolution"
37
39
"github.com/operator-framework/operator-controller/internal/resolution/variable_sources/bundles_and_dependencies"
40
+ "github.com/operator-framework/operator-controller/internal/resolution/variable_sources/entity"
38
41
)
39
42
40
43
// OperatorReconciler reconciles a Operator object
@@ -105,54 +108,87 @@ func checkForUnexpectedFieldChange(a, b operatorsv1alpha1.Operator) bool {
105
108
106
109
// Helper function to do the actual reconcile
107
110
func (r * OperatorReconciler ) reconcile (ctx context.Context , op * operatorsv1alpha1.Operator ) (ctrl.Result , error ) {
108
- // define condition parameters
109
- var status = metav1 .ConditionTrue
110
- var reason = operatorsv1alpha1 .ReasonResolutionSucceeded
111
- var message = "resolution was successful"
112
-
113
111
// run resolution
114
112
solution , err := r .Resolver .Resolve (ctx )
115
113
if err != nil {
116
- status = metav1 .ConditionFalse
117
- reason = operatorsv1alpha1 .ReasonResolutionFailed
118
- message = err .Error ()
119
- } else {
120
- // extract package bundle path from resolved variable
121
- for _ , variable := range solution .SelectedVariables () {
122
- switch v := variable .(type ) {
123
- case * bundles_and_dependencies.BundleVariable :
124
- packageName , err := v .BundleEntity ().PackageName ()
125
- if err != nil {
126
- return ctrl.Result {}, err
127
- }
128
- if packageName == op .Spec .PackageName {
129
- bundlePath , err := v .BundleEntity ().BundlePath ()
130
- if err != nil {
131
- return ctrl.Result {}, err
132
- }
133
- // Create bundleDeployment if not found or Update if needed
134
- dep := r .generateExpectedBundleDeployment (* op , bundlePath )
135
- if err := r .ensureBundleDeployment (ctx , dep ); err != nil {
136
- return ctrl.Result {}, err
137
- }
138
- break
139
- }
140
- }
141
- }
114
+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
115
+ Type : operatorsv1alpha1 .TypeReady ,
116
+ Status : metav1 .ConditionFalse ,
117
+ Reason : operatorsv1alpha1 .ReasonResolutionFailed ,
118
+ Message : err .Error (),
119
+ ObservedGeneration : op .GetGeneration (),
120
+ })
121
+ return ctrl.Result {}, err
122
+ }
123
+
124
+ // lookup the bundle entity in the solution that corresponds to the
125
+ // Operator's desired package name.
126
+ bundleEntity , err := r .getBundleEntityFromSolution (solution , op .Spec .PackageName )
127
+ if err != nil {
128
+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
129
+ Type : operatorsv1alpha1 .TypeReady ,
130
+ Status : metav1 .ConditionFalse ,
131
+ Reason : operatorsv1alpha1 .ReasonBundleLookupFailed ,
132
+ Message : err .Error (),
133
+ ObservedGeneration : op .GetGeneration (),
134
+ })
135
+ return ctrl.Result {}, err
136
+ }
137
+
138
+ // Get the bundle image reference for the bundle
139
+ bundleImage , err := bundleEntity .BundlePath ()
140
+ if err != nil {
141
+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
142
+ Type : operatorsv1alpha1 .TypeReady ,
143
+ Status : metav1 .ConditionFalse ,
144
+ Reason : operatorsv1alpha1 .ReasonBundleLookupFailed ,
145
+ Message : err .Error (),
146
+ ObservedGeneration : op .GetGeneration (),
147
+ })
148
+ return ctrl.Result {}, err
149
+ }
150
+
151
+ // Ensure a BundleDeployment exists with its bundle source from the bundle
152
+ // image we just looked up in the solution.
153
+ dep := r .generateExpectedBundleDeployment (* op , bundleImage )
154
+ if err := r .ensureBundleDeployment (ctx , dep ); err != nil {
155
+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
156
+ Type : operatorsv1alpha1 .TypeReady ,
157
+ Status : metav1 .ConditionFalse ,
158
+ Reason : operatorsv1alpha1 .ReasonBundleDeploymentFailed ,
159
+ Message : err .Error (),
160
+ ObservedGeneration : op .GetGeneration (),
161
+ })
162
+ return ctrl.Result {}, err
142
163
}
143
164
144
165
// update operator status
145
166
apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
146
167
Type : operatorsv1alpha1 .TypeReady ,
147
- Status : status ,
148
- Reason : reason ,
149
- Message : message ,
168
+ Status : metav1 . ConditionTrue ,
169
+ Reason : operatorsv1alpha1 . ReasonResolutionSucceeded ,
170
+ Message : "resolution was successful" ,
150
171
ObservedGeneration : op .GetGeneration (),
151
172
})
152
-
153
173
return ctrl.Result {}, nil
154
174
}
155
175
176
+ func (r * OperatorReconciler ) getBundleEntityFromSolution (solution * solver.Solution , packageName string ) (* entity.BundleEntity , error ) {
177
+ for _ , variable := range solution .SelectedVariables () {
178
+ switch v := variable .(type ) {
179
+ case * bundles_and_dependencies.BundleVariable :
180
+ entityPkgName , err := v .BundleEntity ().PackageName ()
181
+ if err != nil {
182
+ return nil , err
183
+ }
184
+ if packageName == entityPkgName {
185
+ return v .BundleEntity (), nil
186
+ }
187
+ }
188
+ }
189
+ return nil , fmt .Errorf ("entity for package %q not found in solution" , packageName )
190
+ }
191
+
156
192
func (r * OperatorReconciler ) generateExpectedBundleDeployment (o operatorsv1alpha1.Operator , bundlePath string ) * unstructured.Unstructured {
157
193
// We use unstructured here to avoid problems of serializing default values when sending patches to the apiserver.
158
194
// If you use a typed object, any default values from that struct get serialized into the JSON patch, which could
0 commit comments