@@ -154,8 +154,15 @@ async def try_delete(logger, resource, instances, **kwargs):
154154 return check_required
155155
156156
157- async def purge_openstack_resources (
158- logger , clouds , cloud_name , cacert , name , include_volumes , include_appcred
157+ async def purge_openstack_resources ( # noqa: C901
158+ logger ,
159+ clouds ,
160+ cloud_name ,
161+ cacert ,
162+ name ,
163+ include_volumes ,
164+ include_loadbalancers ,
165+ include_appcred ,
159166):
160167 """Cleans up the OpenStack resources created by the OCCM and CSI for a cluster."""
161168 # Use the credential to delete external resources as required
@@ -180,10 +187,15 @@ async def purge_openstack_resources(
180187 # Delete any loadbalancers associated with loadbalancer services for the cluster
181188 lbapi = cloud .api_client ("load-balancer" , "/v2/lbaas/" )
182189 loadbalancers = lbapi .resource ("loadbalancers" )
183- check_lbs = await try_delete (
184- logger , loadbalancers , lbs_for_cluster (loadbalancers , name ), cascade = "true"
185- )
186- logger .info ("deleted load balancers for LoadBalancer services" )
190+ check_lbs = False
191+ if include_loadbalancers :
192+ check_lbs = await try_delete (
193+ logger ,
194+ loadbalancers ,
195+ lbs_for_cluster (loadbalancers , name ),
196+ cascade = "true" ,
197+ )
198+ logger .info ("deleted load balancers for LoadBalancer services" )
187199
188200 # Delete security groups associated with loadbalancer services for the cluster
189201 secgroups = networkapi .resource ("security-groups" )
@@ -344,15 +356,15 @@ async def wrapper(**kwargs):
344356@kopf .on .event (CAPO_API_GROUP , "openstackclusters" )
345357@retry_event
346358async def on_openstackcluster_event (
347- name , namespace , meta , labels , spec , logger , ** kwargs
359+ name , namespace , meta , labels , spec , status , logger , ** kwargs
348360):
349361 await _on_openstackcluster_event_impl (
350- name , namespace , meta , labels , spec , logger , ** kwargs
362+ name , namespace , meta , labels , spec , status , logger , ** kwargs
351363 )
352364
353365
354366async def _on_openstackcluster_event_impl (
355- name , namespace , meta , labels , spec , logger , ** kwargs
367+ name , namespace , meta , labels , spec , status , logger , ** kwargs
356368):
357369 """Executes whenever an event occurs for an OpenStack cluster."""
358370 # Get the resource for manipulating OpenStackClusters at the preferred version
@@ -421,15 +433,29 @@ async def _on_openstackcluster_event_impl(
421433 )
422434 remove_appcred = credential_annotation_value == CREDENTIAL_ANNOTATION_DELETE
423435
436+ # Handle the case where the API server load balancer is enabled but was
437+ # never successfully created (possibly due to LB permissions error)
438+ # meaning that there cannot be any other LBs to remove
439+ # (since API server was never online due to missing load balancer)
440+ remove_loadbalancers = (
441+ # Default to false since this is default CAPO behaviour if
442+ # ApiServerLoadBalancer field is omitted from OpenStackClusterSpec
443+ # https://github.com/kubernetes-sigs/cluster-api-provider-openstack/blob/57ae27ee114bda3606d92163397697b640272673/api/v1beta1/openstackcluster_types.go#L99-L101
444+ spec .get ("apiServerLoadBalancer" , {}).get ("enabled" , False )
445+ and status .get ("apiServerLoadBalancer" , {}).get ("id" , "" ) != ""
446+ )
447+
424448 await purge_openstack_resources (
425449 logger ,
426450 clouds ,
427451 cloud_name ,
428452 cacert ,
429453 clustername ,
430454 volumes_annotation_value == VOLUMES_ANNOTATION_DELETE ,
455+ remove_loadbalancers ,
431456 remove_appcred and len (finalizers ) == 1 ,
432457 )
458+
433459 # If we get to here, OpenStack resources have been successfully deleted
434460 # So we can remove the appcred secret if we are the last actor
435461 if remove_appcred and len (finalizers ) == 1 :
0 commit comments