@@ -31,6 +31,7 @@ import (
3131 "k8s.io/apimachinery/pkg/util/wait"
3232 utilsnet "k8s.io/utils/net"
3333 "k8s.io/utils/ptr"
34+ ctrl "sigs.k8s.io/controller-runtime"
3435
3536 infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
3637 "sigs.k8s.io/cluster-api-provider-openstack/pkg/record"
@@ -41,12 +42,16 @@ import (
4142)
4243
4344const (
44- networkPrefix string = "k8s-clusterapi"
45- kubeapiLBSuffix string = "kubeapi"
46- resolvedMsg string = "ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address"
45+ networkPrefix string = "k8s-clusterapi"
46+ kubeapiLBSuffix string = "kubeapi"
47+ resolvedMsg string = "ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address"
48+ waitForOctaviaLBCleanup = 15 * time .Second
4749)
4850
49- const loadBalancerProvisioningStatusActive = "ACTIVE"
51+ const (
52+ loadBalancerProvisioningStatusActive = "ACTIVE"
53+ loadBalancerProvisioningStatusPendingDelete = "PENDING_DELETE"
54+ )
5055
5156// We wrap the LookupHost function in a variable to allow overriding it in unit tests.
5257//
@@ -658,32 +663,40 @@ func (s *Service) ReconcileLoadBalancerMember(openStackCluster *infrav1.OpenStac
658663 return nil
659664}
660665
661- func (s * Service ) DeleteLoadBalancer (openStackCluster * infrav1.OpenStackCluster , clusterResourceName string ) error {
666+ func (s * Service ) DeleteLoadBalancer (openStackCluster * infrav1.OpenStackCluster , clusterResourceName string ) ( result * ctrl. Result , reterr error ) {
662667 loadBalancerName := getLoadBalancerName (clusterResourceName )
663668 lb , err := s .checkIfLbExists (loadBalancerName )
664669 if err != nil {
665- return err
670+ return nil , err
666671 }
667672
668673 if lb == nil {
669- return nil
674+ return nil , nil
675+ }
676+
677+ // If the load balancer is already in PENDING_DELETE state, we don't need to do anything.
678+ // However we should still wait for the load balancer to be deleted which is why we
679+ // request a new reconcile after a certain amount of time.
680+ if lb .ProvisioningStatus == loadBalancerProvisioningStatusPendingDelete {
681+ s .scope .Logger ().Info ("Load balancer is already in PENDING_DELETE state" , "name" , loadBalancerName )
682+ return & ctrl.Result {RequeueAfter : waitForOctaviaLBCleanup }, nil
670683 }
671684
672685 if lb .VipPortID != "" {
673686 fip , err := s .networkingService .GetFloatingIPByPortID (lb .VipPortID )
674687 if err != nil {
675- return err
688+ return nil , err
676689 }
677690
678691 if fip != nil && fip .FloatingIP != "" {
679692 if err = s .networkingService .DisassociateFloatingIP (openStackCluster , fip .FloatingIP ); err != nil {
680- return err
693+ return nil , err
681694 }
682695
683696 // If the floating is user-provider (BYO floating IP), don't delete it.
684697 if openStackCluster .Spec .APIServerFloatingIP == nil || * openStackCluster .Spec .APIServerFloatingIP != fip .FloatingIP {
685698 if err = s .networkingService .DeleteFloatingIP (openStackCluster , fip .FloatingIP ); err != nil {
686- return err
699+ return nil , err
687700 }
688701 } else {
689702 s .scope .Logger ().Info ("Skipping load balancer floating IP deletion as it's a user-provided resource" , "name" , loadBalancerName , "fip" , fip .FloatingIP )
@@ -698,11 +711,14 @@ func (s *Service) DeleteLoadBalancer(openStackCluster *infrav1.OpenStackCluster,
698711 err = s .loadbalancerClient .DeleteLoadBalancer (lb .ID , deleteOpts )
699712 if err != nil && ! capoerrors .IsNotFound (err ) {
700713 record .Warnf (openStackCluster , "FailedDeleteLoadBalancer" , "Failed to delete load balancer %s with id %s: %v" , lb .Name , lb .ID , err )
701- return err
714+ return nil , err
702715 }
703716
704717 record .Eventf (openStackCluster , "SuccessfulDeleteLoadBalancer" , "Deleted load balancer %s with id %s" , lb .Name , lb .ID )
705- return nil
718+
719+ // If we have reached this point, that means that the load balancer wasn't initially deleted but the request to delete it didn't return an error.
720+ // So we want to requeue until the load balancer and its associated ports are actually deleted.
721+ return & ctrl.Result {RequeueAfter : waitForOctaviaLBCleanup }, nil
706722}
707723
708724func (s * Service ) DeleteLoadBalancerMember (openStackCluster * infrav1.OpenStackCluster , openStackMachine * infrav1.OpenStackMachine , clusterResourceName string ) error {
0 commit comments