func()

in pkg/openstack/loadbalancer.go [3047:3234]


func (lbaas *LbaasV2) ensureLoadBalancerDeleted(ctx context.Context, clusterName string, service *corev1.Service) error {
	lbName := lbaas.GetLoadBalancerName(ctx, clusterName, service)
	legacyName := lbaas.getLoadBalancerLegacyName(ctx, clusterName, service)
	var err error
	var loadbalancer *loadbalancers.LoadBalancer
	isSharedLB := false
	updateLBTag := false
	isCreatedByOCCM := false

	svcConf := new(serviceConfig)
	if err := lbaas.checkServiceDelete(service, svcConf); err != nil {
		return err
	}

	if svcConf.lbID != "" {
		loadbalancer, err = openstackutil.GetLoadbalancerByID(lbaas.lb, svcConf.lbID)
	} else {
		// This may happen when this Service creation was failed previously.
		loadbalancer, err = getLoadbalancerByName(lbaas.lb, lbName, legacyName)
	}
	if err != nil && err != cpoerrors.ErrNotFound {
		return err
	}
	if loadbalancer == nil {
		return nil
	}

	if loadbalancer.ProvisioningStatus != activeStatus {
		return fmt.Errorf("load balancer %s is not ACTIVE, current provisioning status: %s", loadbalancer.ID, loadbalancer.ProvisioningStatus)
	}

	if strings.HasPrefix(loadbalancer.Name, servicePrefix) {
		isCreatedByOCCM = true
	}

	if svcConf.supportLBTags {
		for _, tag := range loadbalancer.Tags {
			if tag == lbName {
				updateLBTag = true
			} else if strings.HasPrefix(tag, servicePrefix) {
				isSharedLB = true
			}
		}
	}

	// If the LB is shared by other Service or the LB was not created by occm, the LB should not be deleted.
	needDeleteLB := true
	if isSharedLB || !isCreatedByOCCM {
		needDeleteLB = false
	}

	klog.V(4).InfoS("Deleting service", "service", klog.KObj(service), "needDeleteLB", needDeleteLB, "isSharedLB", isSharedLB, "updateLBTag", updateLBTag, "isCreatedByOCCM", isCreatedByOCCM)

	keepFloatingAnnotation := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerKeepFloatingIP, false)
	if needDeleteLB && !keepFloatingAnnotation {
		if loadbalancer.VipPortID != "" {
			portID := loadbalancer.VipPortID
			fip, err := openstackutil.GetFloatingIPByPortID(lbaas.network, portID)
			if err != nil {
				return fmt.Errorf("failed to get floating IP for loadbalancer VIP port %s: %v", portID, err)
			}

			// Delete the floating IP only if it was created dynamically by the controller manager.
			if fip != nil {
				klog.InfoS("Matching floating IP", "floatingIP", fip.FloatingIP, "description", fip.Description)
				matched, err := regexp.Match("Floating IP for Kubernetes external service", []byte(fip.Description))
				if err != nil {
					return err
				}

				if matched {
					klog.InfoS("Deleting floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
					mc := metrics.NewMetricContext("floating_ip", "delete")
					err := floatingips.Delete(lbaas.network, fip.ID).ExtractErr()
					if mc.ObserveRequest(err) != nil {
						return fmt.Errorf("failed to delete floating IP %s for loadbalancer VIP port %s: %v", fip.FloatingIP, portID, err)
					}
					klog.InfoS("Deleted floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
				}
			}
		}
	}

	// For neutron-lbaas
	if !lbaas.opts.UseOctavia {
		return lbaas.ensureLoadBalancerDeletedLegacy(loadbalancer)
	}

	if needDeleteLB && lbaas.opts.CascadeDelete {
		klog.InfoS("Deleting load balancer", "lbID", loadbalancer.ID, "service", klog.KObj(service))
		if err := openstackutil.DeleteLoadbalancer(lbaas.lb, loadbalancer.ID, true); err != nil {
			return err
		}
		klog.InfoS("Deleted load balancer", "lbID", loadbalancer.ID, "service", klog.KObj(service))
	} else {
		// get all listeners associated with this loadbalancer
		listenerList, err := openstackutil.GetListenersByLoadBalancerID(lbaas.lb, loadbalancer.ID)
		if err != nil {
			return fmt.Errorf("error getting LB %s listeners: %v", loadbalancer.ID, err)
		}

		if !needDeleteLB {
			var listenersToDelete []listeners.Listener
			curListenerMapping := make(map[listenerKey]*listeners.Listener)
			for i, l := range listenerList {
				key := listenerKey{Protocol: listeners.Protocol(l.Protocol), Port: l.ProtocolPort}
				curListenerMapping[key] = &listenerList[i]
			}

			for _, port := range service.Spec.Ports {
				proto := getListenerProtocol(port.Protocol, svcConf)
				listener, isPresent := curListenerMapping[listenerKey{
					Protocol: proto,
					Port:     int(port.Port),
				}]
				if isPresent && cpoutil.Contains(listener.Tags, lbName) {
					listenersToDelete = append(listenersToDelete, *listener)
				}
			}
			listenerList = listenersToDelete
		}

		// get all pools (and health monitors) associated with this loadbalancer
		var monitorIDs []string
		for _, listener := range listenerList {
			pool, err := openstackutil.GetPoolByListener(lbaas.lb, loadbalancer.ID, listener.ID)
			if err != nil && err != openstackutil.ErrNotFound {
				return fmt.Errorf("error getting pool for listener %s: %v", listener.ID, err)
			}
			if pool != nil {
				if pool.MonitorID != "" {
					monitorIDs = append(monitorIDs, pool.MonitorID)
				}
			}
		}

		// delete monitors
		for _, monitorID := range monitorIDs {
			klog.InfoS("Deleting health monitor", "monitorID", monitorID, "lbID", loadbalancer.ID)
			if err := openstackutil.DeleteHealthMonitor(lbaas.lb, monitorID, loadbalancer.ID); err != nil {
				return err
			}
			klog.InfoS("Deleted health monitor", "monitorID", monitorID, "lbID", loadbalancer.ID)
		}

		// delete listeners
		if err := lbaas.deleteListeners(loadbalancer.ID, listenerList); err != nil {
			return err
		}

		if needDeleteLB {
			// delete the loadbalancer in old way, i.e. no cascading.
			klog.InfoS("Deleting load balancer", "lbID", loadbalancer.ID, "service", klog.KObj(service))
			if err := openstackutil.DeleteLoadbalancer(lbaas.lb, loadbalancer.ID, false); err != nil {
				return err
			}
			klog.InfoS("Deleted load balancer", "lbID", loadbalancer.ID, "service", klog.KObj(service))
		}
	}

	// Remove the Service's tag from the load balancer.
	if !needDeleteLB && updateLBTag {
		var newTags []string
		for _, tag := range loadbalancer.Tags {
			if tag != lbName {
				newTags = append(newTags, tag)
			}
		}
		// An empty list won't trigger tags update.
		if len(newTags) == 0 {
			newTags = []string{""}
		}
		klog.InfoS("Updating load balancer tags", "lbID", loadbalancer.ID, "tags", newTags)
		if err := openstackutil.UpdateLoadBalancerTags(lbaas.lb, loadbalancer.ID, newTags); err != nil {
			return err
		}
		klog.InfoS("Updated load balancer tags", "lbID", loadbalancer.ID)
	}

	// Delete the Security Group
	if lbaas.opts.ManageSecurityGroups {
		if err := lbaas.EnsureSecurityGroupDeleted(clusterName, service); err != nil {
			return err
		}
	}

	return nil
}