@@ -126,8 +126,20 @@ func (r *Reconciler) ReconcileResource(ctx context.Context, serviceInstance *kor
126126 serviceInstance .Status .ObservedGeneration = serviceInstance .Generation
127127 log .V (1 ).Info ("set observed generation" , "generation" , serviceInstance .Status .ObservedGeneration )
128128
129+ serviceInstanceAssets , err := r .assets .GetServiceInstanceAssets (ctx , serviceInstance )
130+ if err != nil {
131+ log .Error (err , "failed to get service instance assets" )
132+ return ctrl.Result {}, err
133+ }
134+
135+ osbapiClient , err := r .osbapiClientFactory .CreateClient (ctx , serviceInstanceAssets .ServiceBroker )
136+ if err != nil {
137+ log .Error (err , "failed to create broker client" , "broker" , serviceInstanceAssets .ServiceBroker .Name )
138+ return ctrl.Result {}, fmt .Errorf ("failed to create client for broker %q: %w" , serviceInstanceAssets .ServiceBroker .Name , err )
139+ }
140+
129141 if ! serviceInstance .GetDeletionTimestamp ().IsZero () {
130- return r .finalizeCFServiceInstance (ctx , serviceInstance )
142+ return r .finalizeCFServiceInstance (ctx , serviceInstance , serviceInstanceAssets , osbapiClient )
131143 }
132144
133145 if isReady (serviceInstance ) {
@@ -138,12 +150,6 @@ func (r *Reconciler) ReconcileResource(ctx context.Context, serviceInstance *kor
138150 return ctrl.Result {}, k8s .NewNotReadyError ().WithReason ("ProvisioningFailed" ).WithNoRequeue ()
139151 }
140152
141- serviceInstanceAssets , err := r .assets .GetServiceInstanceAssets (ctx , serviceInstance )
142- if err != nil {
143- log .Error (err , "failed to get service instance assets" )
144- return ctrl.Result {}, err
145- }
146-
147153 planVisible , err := r .isServicePlanVisible (ctx , serviceInstance , serviceInstanceAssets .ServicePlan )
148154 if err != nil {
149155 log .Error (err , "failed to check service plan visibility" )
@@ -159,52 +165,24 @@ func (r *Reconciler) ReconcileResource(ctx context.Context, serviceInstance *kor
159165 serviceInstance .Spec .ServiceLabel = tools .PtrTo (serviceInstanceAssets .ServiceOffering .Spec .Name )
160166 }
161167
162- osbapiClient , err := r .osbapiClientFactory .CreateClient (ctx , serviceInstanceAssets .ServiceBroker )
163- if err != nil {
164- log .Error (err , "failed to create broker client" , "broker" , serviceInstanceAssets .ServiceBroker .Name )
165- return ctrl.Result {}, fmt .Errorf ("failed to create client for broker %q: %w" , serviceInstanceAssets .ServiceBroker .Name , err )
166- }
167-
168168 provisionResponse , err := r .provisionServiceInstance (ctx , serviceInstance , serviceInstanceAssets , osbapiClient )
169169 if err != nil {
170170 log .Error (err , "failed to provision service instance" )
171171 return ctrl.Result {}, fmt .Errorf ("failed to provision service instance: %w" , err )
172172 }
173173
174174 if provisionResponse .IsAsync {
175- return r .pollProvisionOperation (ctx , serviceInstance , serviceInstanceAssets , osbapiClient , provisionResponse .Operation )
175+ lastOpResponse , err := r .pollLastOperation (ctx , serviceInstance , serviceInstanceAssets , osbapiClient , provisionResponse .Operation )
176+ if err != nil {
177+ return ctrl.Result {}, err
178+ }
179+ return r .processProvisionOperation (serviceInstance , lastOpResponse )
176180 }
177181
178182 serviceInstance .Status .LastOperation .State = "succeeded"
179183 return ctrl.Result {}, nil
180184}
181185
182- func (r * Reconciler ) isServicePlanVisible (
183- ctx context.Context ,
184- serviceInstance * korifiv1alpha1.CFServiceInstance ,
185- servicePlan * korifiv1alpha1.CFServicePlan ,
186- ) (bool , error ) {
187- if servicePlan .Spec .Visibility .Type == korifiv1alpha1 .AdminServicePlanVisibilityType {
188- return false , nil
189- }
190-
191- if servicePlan .Spec .Visibility .Type == korifiv1alpha1 .PublicServicePlanVisibilityType {
192- return true , nil
193- }
194-
195- namespace := & corev1.Namespace {
196- ObjectMeta : metav1.ObjectMeta {
197- Name : serviceInstance .Namespace ,
198- },
199- }
200- err := r .k8sClient .Get (ctx , client .ObjectKeyFromObject (namespace ), namespace )
201- if err != nil {
202- return false , err
203- }
204-
205- return slices .Contains (servicePlan .Spec .Visibility .Organizations , namespace .Labels [korifiv1alpha1 .OrgGUIDKey ]), nil
206- }
207-
208186func (r * Reconciler ) provisionServiceInstance (
209187 ctx context.Context ,
210188 serviceInstance * korifiv1alpha1.CFServiceInstance ,
@@ -265,31 +243,10 @@ func (r *Reconciler) provisionServiceInstance(
265243 return provisionResponse , nil
266244}
267245
268- func (r * Reconciler ) pollProvisionOperation (
269- ctx context.Context ,
246+ func (r * Reconciler ) processProvisionOperation (
270247 serviceInstance * korifiv1alpha1.CFServiceInstance ,
271- assets osbapi.ServiceInstanceAssets ,
272- osbapiClient osbapi.BrokerClient ,
273- operationID string ,
248+ lastOpResponse osbapi.LastOperationResponse ,
274249) (ctrl.Result , error ) {
275- log := logr .FromContextOrDiscard (ctx ).WithName ("poll-provision-operation" )
276-
277- lastOpResponse , err := osbapiClient .GetServiceInstanceLastOperation (ctx , osbapi.GetServiceInstanceLastOperationRequest {
278- InstanceID : serviceInstance .Name ,
279- GetLastOperationRequestParameters : osbapi.GetLastOperationRequestParameters {
280- ServiceId : assets .ServiceOffering .Spec .BrokerCatalog .ID ,
281- PlanID : assets .ServicePlan .Spec .BrokerCatalog .ID ,
282- Operation : operationID ,
283- },
284- })
285- if err != nil {
286- log .Error (err , "getting service instance last operation failed" )
287- return ctrl.Result {}, k8s .NewNotReadyError ().WithCause (err ).WithReason ("GetLastOperationFailed" )
288- }
289-
290- serviceInstance .Status .LastOperation .State = lastOpResponse .State
291- serviceInstance .Status .LastOperation .Description = lastOpResponse .Description
292-
293250 if lastOpResponse .State == "in progress" {
294251 return ctrl.Result {}, k8s .NewNotReadyError ().WithReason ("ProvisionInProgress" ).WithRequeue ()
295252 }
@@ -309,33 +266,31 @@ func (r *Reconciler) pollProvisionOperation(
309266 return ctrl.Result {}, nil
310267}
311268
312- func getServiceInstanceParameters (serviceInstance * korifiv1alpha1.CFServiceInstance ) (map [string ]any , error ) {
313- if serviceInstance .Spec .Parameters == nil {
314- return nil , nil
315- }
316-
317- parametersMap := map [string ]any {}
318- err := json .Unmarshal (serviceInstance .Spec .Parameters .Raw , & parametersMap )
319- if err != nil {
320- return nil , fmt .Errorf ("failed to unmarshal parameters: %w" , err )
321- }
322-
323- return parametersMap , nil
324- }
325-
326269func (r * Reconciler ) finalizeCFServiceInstance (
327270 ctx context.Context ,
328271 serviceInstance * korifiv1alpha1.CFServiceInstance ,
272+ assets osbapi.ServiceInstanceAssets ,
273+ osbapiClient osbapi.BrokerClient ,
329274) (ctrl.Result , error ) {
330275 log := logr .FromContextOrDiscard (ctx ).WithName ("finalizeCFServiceInstance" )
331276
332277 if ! controllerutil .ContainsFinalizer (serviceInstance , korifiv1alpha1 .CFServiceInstanceFinalizerName ) {
333278 return ctrl.Result {}, nil
334279 }
335280
336- _ , err := r .deprovisionServiceInstance (ctx , serviceInstance )
281+ deprovisionResponse , err := r .deprovisionServiceInstance (ctx , serviceInstance , assets , osbapiClient )
337282 if err != nil {
338283 log .Error (err , "failed to deprovision service instance with broker" )
284+ return ctrl.Result {}, err
285+ }
286+
287+ if deprovisionResponse .IsAsync {
288+
289+ lastOpResponse , err := r .pollLastOperation (ctx , serviceInstance , assets , osbapiClient , deprovisionResponse .Operation )
290+ if err != nil {
291+ return ctrl.Result {}, err
292+ }
293+ return r .processDeprovisionOperation (serviceInstance , lastOpResponse )
339294 }
340295
341296 controllerutil .RemoveFinalizer (serviceInstance , korifiv1alpha1 .CFServiceInstanceFinalizerName )
@@ -347,32 +302,130 @@ func (r *Reconciler) finalizeCFServiceInstance(
347302func (r * Reconciler ) deprovisionServiceInstance (
348303 ctx context.Context ,
349304 serviceInstance * korifiv1alpha1.CFServiceInstance ,
305+ assets osbapi.ServiceInstanceAssets ,
306+ osbapiClient osbapi.BrokerClient ,
350307) (osbapi.ServiceInstanceOperationResponse , error ) {
351- assets , err := r .assets .GetServiceInstanceAssets (ctx , serviceInstance )
352- if err != nil {
353- return osbapi.ServiceInstanceOperationResponse {}, fmt .Errorf ("failed to get service instance assets: %w" , err )
354- }
355-
356- osbapiClient , err := r .osbapiClientFactory .CreateClient (ctx , assets .ServiceBroker )
357- if err != nil {
358- return osbapi.ServiceInstanceOperationResponse {}, fmt .Errorf ("failed to create broker client: %w" , err )
308+ serviceInstance .Status .LastOperation = services.LastOperation {
309+ Type : "delete" ,
310+ State : "initial" ,
359311 }
360-
361- var deprovisionResponse osbapi.ServiceInstanceOperationResponse
362- deprovisionResponse , err = osbapiClient .Deprovision (ctx , osbapi.InstanceDeprovisionPayload {
312+ deprovisionResponse , err := osbapiClient .Deprovision (ctx , osbapi.InstanceDeprovisionPayload {
363313 ID : serviceInstance .Name ,
364314 InstanceDeprovisionRequest : osbapi.InstanceDeprovisionRequest {
365315 ServiceId : assets .ServiceOffering .Spec .BrokerCatalog .ID ,
366316 PlanID : assets .ServicePlan .Spec .BrokerCatalog .ID ,
367317 },
368318 })
369319 if err != nil {
320+ if osbapi .IsUnrecoveralbeError (err ) {
321+ serviceInstance .Status .LastOperation .State = "failed"
322+ meta .SetStatusCondition (& serviceInstance .Status .Conditions , metav1.Condition {
323+ Type : korifiv1alpha1 .DeprovisioningFailedCondition ,
324+ Status : metav1 .ConditionTrue ,
325+ ObservedGeneration : serviceInstance .Generation ,
326+ LastTransitionTime : metav1 .NewTime (time .Now ()),
327+ Reason : "DeprovisionFailed" ,
328+ Message : err .Error (),
329+ })
330+ return osbapi.ServiceInstanceOperationResponse {},
331+ k8s .NewNotReadyError ().WithReason ("DeprovisionFailed" )
332+ }
333+
370334 return osbapi.ServiceInstanceOperationResponse {}, fmt .Errorf ("failed to deprovision service instance: %w" , err )
371335 }
372336
373337 return deprovisionResponse , nil
374338}
375339
340+ func (r * Reconciler ) processDeprovisionOperation (
341+ serviceInstance * korifiv1alpha1.CFServiceInstance ,
342+ lastOpResponse osbapi.LastOperationResponse ,
343+ ) (ctrl.Result , error ) {
344+ if lastOpResponse .State == "in progress" {
345+ return ctrl.Result {}, k8s .NewNotReadyError ().WithReason ("DeprovisionInProgress" ).WithRequeue ()
346+ }
347+
348+ if lastOpResponse .State == "failed" {
349+ meta .SetStatusCondition (& serviceInstance .Status .Conditions , metav1.Condition {
350+ Type : korifiv1alpha1 .DeprovisioningFailedCondition ,
351+ Status : metav1 .ConditionTrue ,
352+ ObservedGeneration : serviceInstance .Generation ,
353+ LastTransitionTime : metav1 .NewTime (time .Now ()),
354+ Reason : "DeprovisionFailed" ,
355+ Message : lastOpResponse .Description ,
356+ })
357+ return ctrl.Result {}, k8s .NewNotReadyError ().WithReason ("DeprovisionFailed" )
358+ }
359+
360+ return ctrl.Result {}, nil
361+ }
362+
363+ func (r * Reconciler ) pollLastOperation (
364+ ctx context.Context ,
365+ serviceInstance * korifiv1alpha1.CFServiceInstance ,
366+ assets osbapi.ServiceInstanceAssets ,
367+ osbapiClient osbapi.BrokerClient ,
368+ operationID string ,
369+ ) (osbapi.LastOperationResponse , error ) {
370+ log := logr .FromContextOrDiscard (ctx ).WithName ("poll-operation" )
371+ lastOpResponse , err := osbapiClient .GetServiceInstanceLastOperation (ctx , osbapi.GetServiceInstanceLastOperationRequest {
372+ InstanceID : serviceInstance .Name ,
373+ GetLastOperationRequestParameters : osbapi.GetLastOperationRequestParameters {
374+ ServiceId : assets .ServiceOffering .Spec .BrokerCatalog .ID ,
375+ PlanID : assets .ServicePlan .Spec .BrokerCatalog .ID ,
376+ Operation : operationID ,
377+ },
378+ })
379+ if err != nil {
380+ log .Error (err , "getting service instance last operation failed" )
381+ return osbapi.LastOperationResponse {}, k8s .NewNotReadyError ().WithCause (err ).WithReason ("GetLastOperationFailed" )
382+ }
383+
384+ serviceInstance .Status .LastOperation .State = lastOpResponse .State
385+ serviceInstance .Status .LastOperation .Description = lastOpResponse .Description
386+ return lastOpResponse , nil
387+ }
388+
389+ func getServiceInstanceParameters (serviceInstance * korifiv1alpha1.CFServiceInstance ) (map [string ]any , error ) {
390+ if serviceInstance .Spec .Parameters == nil {
391+ return nil , nil
392+ }
393+
394+ parametersMap := map [string ]any {}
395+ err := json .Unmarshal (serviceInstance .Spec .Parameters .Raw , & parametersMap )
396+ if err != nil {
397+ return nil , fmt .Errorf ("failed to unmarshal parameters: %w" , err )
398+ }
399+
400+ return parametersMap , nil
401+ }
402+
403+ func (r * Reconciler ) isServicePlanVisible (
404+ ctx context.Context ,
405+ serviceInstance * korifiv1alpha1.CFServiceInstance ,
406+ servicePlan * korifiv1alpha1.CFServicePlan ,
407+ ) (bool , error ) {
408+ if servicePlan .Spec .Visibility .Type == korifiv1alpha1 .AdminServicePlanVisibilityType {
409+ return false , nil
410+ }
411+
412+ if servicePlan .Spec .Visibility .Type == korifiv1alpha1 .PublicServicePlanVisibilityType {
413+ return true , nil
414+ }
415+
416+ namespace := & corev1.Namespace {
417+ ObjectMeta : metav1.ObjectMeta {
418+ Name : serviceInstance .Namespace ,
419+ },
420+ }
421+ err := r .k8sClient .Get (ctx , client .ObjectKeyFromObject (namespace ), namespace )
422+ if err != nil {
423+ return false , err
424+ }
425+
426+ return slices .Contains (servicePlan .Spec .Visibility .Organizations , namespace .Labels [korifiv1alpha1 .OrgGUIDKey ]), nil
427+ }
428+
376429func (r * Reconciler ) getNamespace (ctx context.Context , namespaceName string ) (* corev1.Namespace , error ) {
377430 namespace := & corev1.Namespace {
378431 ObjectMeta : metav1.ObjectMeta {
0 commit comments