@@ -18,6 +18,7 @@ package controllers
1818
1919import (
2020 "context"
21+ "fmt"
2122
2223 rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
2324 "k8s.io/apimachinery/pkg/api/equality"
@@ -26,6 +27,7 @@ import (
2627 "k8s.io/apimachinery/pkg/runtime"
2728 "k8s.io/apimachinery/pkg/types"
2829 utilerrors "k8s.io/apimachinery/pkg/util/errors"
30+ "k8s.io/utils/pointer"
2931 ctrl "sigs.k8s.io/controller-runtime"
3032 "sigs.k8s.io/controller-runtime/pkg/client"
3133 "sigs.k8s.io/controller-runtime/pkg/log"
@@ -38,23 +40,13 @@ import (
3840// OperatorReconciler reconciles a Operator object
3941type OperatorReconciler struct {
4042 client.Client
41- Scheme * runtime.Scheme
42-
43- resolver * resolution.OperatorResolver
44- }
45-
46- func NewOperatorReconciler (c client.Client , s * runtime.Scheme , r * resolution.OperatorResolver ) * OperatorReconciler {
47- return & OperatorReconciler {
48- Client : c ,
49- Scheme : s ,
50- resolver : r ,
51- }
43+ Scheme * runtime.Scheme
44+ Resolver * resolution.OperatorResolver
5245}
5346
54- //+kubebuilder:rbac:groups=operators.operatorframework.io,resources=operators,verbs=get;list;watch;create;update;patch;delete
47+ //+kubebuilder:rbac:groups=operators.operatorframework.io,resources=operators,verbs=get;list;watch
5548//+kubebuilder:rbac:groups=operators.operatorframework.io,resources=operators/status,verbs=get;update;patch
5649//+kubebuilder:rbac:groups=operators.operatorframework.io,resources=operators/finalizers,verbs=update
57-
5850//+kubebuilder:rbac:groups=core.rukpak.io,resources=bundledeployments,verbs=get;list;watch;create;update;patch
5951
6052// Reconcile is part of the main kubernetes reconciliation loop which aims to
@@ -112,61 +104,105 @@ func checkForUnexpectedFieldChange(a, b operatorsv1alpha1.Operator) bool {
112104
113105// Helper function to do the actual reconcile
114106func (r * OperatorReconciler ) reconcile (ctx context.Context , op * operatorsv1alpha1.Operator ) (ctrl.Result , error ) {
115- // define condition parameters
116- var status = metav1 .ConditionTrue
117- var reason = operatorsv1alpha1 .ReasonResolutionSucceeded
118- var message = "resolution was successful"
119107
120108 // run resolution
121- solution , err := r .resolver .Resolve (ctx )
109+ solution , err := r .Resolver .Resolve (ctx )
122110 if err != nil {
123- status = metav1 .ConditionTrue
124- reason = operatorsv1alpha1 .ReasonResolutionFailed
125- message = err .Error ()
126- } else {
127- // extract package bundle path from resolved variable
128- for _ , variable := range solution .SelectedVariables () {
129- switch v := variable .(type ) {
130- case * bundles_and_dependencies.BundleVariable :
131- packageName , err := v .BundleEntity ().PackageName ()
111+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
112+ Type : operatorsv1alpha1 .TypeReady ,
113+ Status : metav1 .ConditionFalse ,
114+ Reason : operatorsv1alpha1 .ReasonResolutionFailed ,
115+ Message : err .Error (),
116+ ObservedGeneration : op .GetGeneration (),
117+ })
118+ return ctrl.Result {}, nil
119+ }
120+
121+ // extract package bundle path from resolved variable
122+ packageFound := false
123+ for _ , variable := range solution .SelectedVariables () {
124+ switch v := variable .(type ) {
125+ case * bundles_and_dependencies.BundleVariable :
126+ packageName , err := v .BundleEntity ().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+ if packageName == op .Spec .PackageName {
138+ bundlePath , err := v .BundleEntity ().BundlePath ()
132139 if err != nil {
140+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
141+ Type : operatorsv1alpha1 .TypeReady ,
142+ Status : metav1 .ConditionFalse ,
143+ Reason : operatorsv1alpha1 .ReasonBundleLookupFailed ,
144+ Message : err .Error (),
145+ ObservedGeneration : op .GetGeneration (),
146+ })
133147 return ctrl.Result {}, err
134148 }
135- if packageName == op .Spec .PackageName {
136- bundlePath , err := v .BundleEntity ().BundlePath ()
137- if err != nil {
138- return ctrl.Result {}, err
139- }
140- dep , err := r .generateExpectedBundleDeployment (* op , bundlePath )
141- if err != nil {
142- return ctrl.Result {}, err
143- }
144- // Create bundleDeployment if not found or Update if needed
145- if err := r .ensureBundleDeployment (ctx , dep ); err != nil {
146- return ctrl.Result {}, err
147- }
148- break
149+ dep := r .generateExpectedBundleDeployment (* op , bundlePath )
150+ // Create bundleDeployment if not found or Update if needed
151+ if err := r .ensureBundleDeployment (ctx , dep ); err != nil {
152+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
153+ Type : operatorsv1alpha1 .TypeReady ,
154+ Status : metav1 .ConditionFalse ,
155+ Reason : operatorsv1alpha1 .ReasonBundleDeploymentFailed ,
156+ Message : err .Error (),
157+ ObservedGeneration : op .GetGeneration (),
158+ })
159+ return ctrl.Result {}, err
149160 }
161+ packageFound = true
162+ break
150163 }
151164 }
152165 }
166+ if ! packageFound {
167+ // TODO: If this happens, it very likely indicates a bug in our resolver.
168+ // For that reason, should this just panic?
169+ apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
170+ Type : operatorsv1alpha1 .TypeReady ,
171+ Status : metav1 .ConditionFalse ,
172+ Reason : operatorsv1alpha1 .ReasonBundleLookupFailed ,
173+ Message : fmt .Sprintf ("resolved set does not contain expected package %q" , op .Spec .PackageName ),
174+ ObservedGeneration : op .GetGeneration (),
175+ })
176+ return ctrl.Result {}, nil
177+ }
153178
154179 // update operator status
155180 apimeta .SetStatusCondition (& op .Status .Conditions , metav1.Condition {
156181 Type : operatorsv1alpha1 .TypeReady ,
157- Status : status ,
158- Reason : reason ,
159- Message : message ,
182+ Status : metav1 . ConditionTrue ,
183+ Reason : operatorsv1alpha1 . ReasonResolutionSucceeded ,
184+ Message : "resolution was successful" ,
160185 ObservedGeneration : op .GetGeneration (),
161186 })
162187
163188 return ctrl.Result {}, nil
164189}
165190
166- func (r * OperatorReconciler ) generateExpectedBundleDeployment (o operatorsv1alpha1.Operator , bundlePath string ) (* rukpakv1alpha1.BundleDeployment , error ) {
167- dep := & rukpakv1alpha1.BundleDeployment {
191+ func (r * OperatorReconciler ) generateExpectedBundleDeployment (o operatorsv1alpha1.Operator , bundlePath string ) * rukpakv1alpha1.BundleDeployment {
192+ // TODO: Use unstructured + server side apply?
193+ return & rukpakv1alpha1.BundleDeployment {
168194 ObjectMeta : metav1.ObjectMeta {
169195 Name : o .GetName (),
196+ OwnerReferences : []metav1.OwnerReference {
197+ {
198+ APIVersion : operatorsv1alpha1 .GroupVersion .String (),
199+ Kind : "Operator" ,
200+ Name : o .Name ,
201+ UID : o .UID ,
202+ Controller : pointer .Bool (true ),
203+ BlockOwnerDeletion : pointer .Bool (true ),
204+ },
205+ },
170206 },
171207 Spec : rukpakv1alpha1.BundleDeploymentSpec {
172208 //TODO: Don't assume plain provisioner
@@ -193,11 +229,6 @@ func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha
193229 },
194230 },
195231 }
196-
197- if err := ctrl .SetControllerReference (& o , dep , r .Scheme ); err != nil {
198- return nil , err
199- }
200- return dep , nil
201232}
202233
203234// SetupWithManager sets up the controller with the Manager.
@@ -224,6 +255,9 @@ func (r *OperatorReconciler) ensureBundleDeployment(ctx context.Context, desired
224255 }
225256
226257 // Check if the existing bundleDeployment's spec needs to be updated
258+ //
259+ // FIXME: checking only for spec differences means that we will not fixup
260+ // changes to and removals of desired metadata.
227261 if equality .Semantic .DeepEqual (existingBundleDeployment .Spec , desiredBundleDeployment .Spec ) {
228262 return nil
229263 }
0 commit comments