Skip to content

Commit 98a258c

Browse files
committed
reduce cyclomatic complexity of reconcile method
1 parent 52bbccb commit 98a258c

File tree

2 files changed

+81
-40
lines changed

2 files changed

+81
-40
lines changed

api/v1alpha1/operator_types.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20-
operatorutil "github.com/operator-framework/operator-controller/internal/util"
2120
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
operatorutil "github.com/operator-framework/operator-controller/internal/util"
2223
)
2324

2425
// OperatorSpec defines the desired state of Operator
@@ -32,9 +33,10 @@ const (
3233
// TODO(user): add more Types, here and into init()
3334
TypeReady = "Ready"
3435

35-
ReasonNotImplemented = "NotImplemented"
36-
ReasonResolutionFailed = "ResolutionFailed"
37-
ReasonResolutionSucceeded = "ResolutionSucceeded"
36+
ReasonResolutionSucceeded = "ResolutionSucceeded"
37+
ReasonResolutionFailed = "ResolutionFailed"
38+
ReasonBundleLookupFailed = "BundleLookupFailed"
39+
ReasonBundleDeploymentFailed = "BundleDeploymentFailed"
3840
)
3941

4042
func init() {
@@ -44,7 +46,10 @@ func init() {
4446
)
4547
// TODO(user): add Reasons from above
4648
operatorutil.ConditionReasons = append(operatorutil.ConditionReasons,
47-
ReasonNotImplemented, ReasonResolutionSucceeded, ReasonResolutionFailed,
49+
ReasonResolutionSucceeded,
50+
ReasonResolutionFailed,
51+
ReasonBundleLookupFailed,
52+
ReasonBundleDeploymentFailed,
4853
)
4954
}
5055

controllers/operator_controller.go

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ package controllers
1818

1919
import (
2020
"context"
21+
"fmt"
2122

23+
"github.com/operator-framework/deppy/pkg/deppy/solver"
2224
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
2325
"k8s.io/apimachinery/pkg/api/equality"
2426
apimeta "k8s.io/apimachinery/pkg/api/meta"
@@ -35,6 +37,7 @@ import (
3537
operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
3638
"github.com/operator-framework/operator-controller/internal/resolution"
3739
"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"
3841
)
3942

4043
// OperatorReconciler reconciles a Operator object
@@ -105,54 +108,87 @@ func checkForUnexpectedFieldChange(a, b operatorsv1alpha1.Operator) bool {
105108

106109
// Helper function to do the actual reconcile
107110
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-
113111
// run resolution
114112
solution, err := r.Resolver.Resolve(ctx)
115113
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
142163
}
143164

144165
// update operator status
145166
apimeta.SetStatusCondition(&op.Status.Conditions, metav1.Condition{
146167
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",
150171
ObservedGeneration: op.GetGeneration(),
151172
})
152-
153173
return ctrl.Result{}, nil
154174
}
155175

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+
156192
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string) *unstructured.Unstructured {
157193
// We use unstructured here to avoid problems of serializing default values when sending patches to the apiserver.
158194
// If you use a typed object, any default values from that struct get serialized into the JSON patch, which could

0 commit comments

Comments
 (0)