Skip to content

Commit a7c2d10

Browse files
authored
[occm] Remove FIP on internal annotation addition (#2168)
When the service.beta.kubernetes.io/openstack-internal-load-balancer annotation gets added to a Service we do not reconcile in terms of removal of a FIP that may already exist. This commit fixes that by making sure FIP attached to an LB VIP is deleted.
1 parent 31ce345 commit a7c2d10

File tree

1 file changed

+85
-33
lines changed

1 file changed

+85
-33
lines changed

pkg/openstack/loadbalancer.go

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -908,26 +908,74 @@ func (lbaas *LbaasV2) createFloatingIP(msg string, floatIPOpts floatingips.Creat
908908
return floatIP, err
909909
}
910910

911-
// Priority of choosing VIP port floating IP:
912-
// 1. The floating IP that is already attached to the VIP port.
913-
// 2. Floating IP specified in Spec.LoadBalancerIP
914-
// 3. Create a new one
915-
func (lbaas *LbaasV2) getServiceAddress(clusterName string, service *corev1.Service, lb *loadbalancers.LoadBalancer, svcConf *serviceConfig, isLBOwner bool) (string, error) {
916-
917-
if svcConf.internal {
918-
return lb.VipAddress, nil
911+
func (lbaas *LbaasV2) updateFloatingIP(floatingip *floatingips.FloatingIP, portID *string) (*floatingips.FloatingIP, error) {
912+
floatUpdateOpts := floatingips.UpdateOpts{
913+
PortID: portID,
919914
}
920-
921-
var floatIP *floatingips.FloatingIP
915+
if portID != nil {
916+
klog.V(4).Infof("Attaching floating ip %q to loadbalancer port %q", floatingip.FloatingIP, portID)
917+
} else {
918+
klog.V(4).Infof("Detaching floating ip %q from port %q", floatingip.FloatingIP, floatingip.PortID)
919+
}
920+
mc := metrics.NewMetricContext("floating_ip", "update")
921+
floatingip, err := floatingips.Update(lbaas.network, floatingip.ID, floatUpdateOpts).Extract()
922+
if mc.ObserveRequest(err) != nil {
923+
return nil, fmt.Errorf("error updating LB floatingip %+v: %v", floatUpdateOpts, err)
924+
}
925+
return floatingip, nil
926+
}
927+
928+
// ensureFloatingIP manages a FIP for a Service and returns the address that should be advertised in the
929+
// .Status.LoadBalancer. In particular it will:
930+
// 1. Lookup if any FIP is already attached to the VIP port of the LB.
931+
// a) If it is and Service is internal, it will attempt to detach the FIP and delete it if it was created
932+
// by cloud provider. This is to support cases of changing the internal annotation.
933+
// b) If the Service is not the owner of the LB it will not contiue to prevent accidental exposure of the
934+
// possible internal Services already existing on that LB.
935+
// c) If it's external Service, it will use that existing FIP.
936+
// 2. Lookup FIP specified in Spec.LoadBalancerIP and try to assign it to the LB VIP port.
937+
// 3. Try to create and assign a new FIP:
938+
// a) If Spec.LoadBalancerIP is not set, just create a random FIP in the external network and use that.
939+
// b) If Spec.LoadBalancerIP is specified, try to create a FIP with that address. By default this is not allowed by
940+
// the Neutron policy for regular users!
941+
func (lbaas *LbaasV2) ensureFloatingIP(clusterName string, service *corev1.Service, lb *loadbalancers.LoadBalancer, svcConf *serviceConfig, isLBOwner bool) (string, error) {
922942
serviceName := fmt.Sprintf("%s/%s", service.Namespace, service.Name)
923943

924-
// first attempt: fetch floating IP attached to load balancer's VIP port
944+
// We need to fetch the FIP attached to load balancer's VIP port for both codepaths
925945
portID := lb.VipPortID
926946
floatIP, err := openstackutil.GetFloatingIPByPortID(lbaas.network, portID)
927947
if err != nil {
928948
return "", fmt.Errorf("failed when getting floating IP for port %s: %v", portID, err)
929949
}
930-
klog.V(4).Infof("Found floating ip %v by loadbalancer port id %q", floatIP, portID)
950+
951+
if floatIP != nil {
952+
klog.V(4).Infof("Found floating ip %v by loadbalancer port id %q", floatIP, portID)
953+
}
954+
955+
if svcConf.internal && isLBOwner {
956+
// if we found a FIP, this is an internal service and we are the owner we should attempt to delete it
957+
if floatIP != nil {
958+
keepFloatingAnnotation := getBoolFromServiceAnnotation(service, ServiceAnnotationLoadBalancerKeepFloatingIP, false)
959+
fipDeleted := false
960+
if !keepFloatingAnnotation {
961+
klog.V(4).Infof("Deleting floating IP %v attached to loadbalancer port id %q for internal service %s", floatIP, portID, serviceName)
962+
fipDeleted, err = lbaas.deleteFIPIfCreatedByProvider(floatIP, portID, service)
963+
if err != nil {
964+
return "", err
965+
}
966+
}
967+
if !fipDeleted {
968+
// if FIP wasn't deleted (because of keep-floatingip annotation or not being created by us) we should still detach it
969+
_, err = lbaas.updateFloatingIP(floatIP, nil)
970+
if err != nil {
971+
return "", err
972+
}
973+
}
974+
}
975+
return lb.VipAddress, nil
976+
}
977+
978+
// first attempt: if we've found a FIP attached to LBs VIP port, we'll be using that.
931979

932980
// we cannot add a FIP to a shared LB when we're a secondary Service or we risk adding it to an internal
933981
// Service and exposing it to the world unintentionally.
@@ -952,14 +1000,9 @@ func (lbaas *LbaasV2) getServiceAddress(clusterName string, service *corev1.Serv
9521000
if len(existingIPs) > 0 {
9531001
floatingip := existingIPs[0]
9541002
if len(floatingip.PortID) == 0 {
955-
floatUpdateOpts := floatingips.UpdateOpts{
956-
PortID: &portID,
957-
}
958-
klog.V(4).Infof("Attaching floating ip %q to loadbalancer port %q", floatingip.FloatingIP, portID)
959-
mc := metrics.NewMetricContext("floating_ip", "update")
960-
floatIP, err = floatingips.Update(lbaas.network, floatingip.ID, floatUpdateOpts).Extract()
961-
if mc.ObserveRequest(err) != nil {
962-
return "", fmt.Errorf("error updating LB floatingip %+v: %v", floatUpdateOpts, err)
1003+
floatIP, err = lbaas.updateFloatingIP(&floatingip, &portID)
1004+
if err != nil {
1005+
return "", err
9631006
}
9641007
} else {
9651008
return "", fmt.Errorf("floating IP %s is not available", loadBalancerIP)
@@ -1973,7 +2016,7 @@ func (lbaas *LbaasV2) ensureOctaviaLoadBalancer(ctx context.Context, clusterName
19732016
}
19742017
}
19752018

1976-
addr, err := lbaas.getServiceAddress(clusterName, service, loadbalancer, svcConf, isLBOwner)
2019+
addr, err := lbaas.ensureFloatingIP(clusterName, service, loadbalancer, svcConf, isLBOwner)
19772020
if err != nil {
19782021
return nil, err
19792022
}
@@ -2272,6 +2315,26 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(ctx context.Context, clusterName
22722315
return mc.ObserveReconcile(err)
22732316
}
22742317

2318+
func (lbaas *LbaasV2) deleteFIPIfCreatedByProvider(fip *floatingips.FloatingIP, portID string, service *corev1.Service) (bool, error) {
2319+
matched, err := regexp.Match("Floating IP for Kubernetes external service", []byte(fip.Description))
2320+
if err != nil {
2321+
return false, err
2322+
}
2323+
2324+
if !matched {
2325+
// It's not a FIP created by us, don't touch it.
2326+
return false, nil
2327+
}
2328+
klog.InfoS("Deleting floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
2329+
mc := metrics.NewMetricContext("floating_ip", "delete")
2330+
err = floatingips.Delete(lbaas.network, fip.ID).ExtractErr()
2331+
if mc.ObserveRequest(err) != nil {
2332+
return false, fmt.Errorf("failed to delete floating IP %s for loadbalancer VIP port %s: %v", fip.FloatingIP, portID, err)
2333+
}
2334+
klog.InfoS("Deleted floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
2335+
return true, nil
2336+
}
2337+
22752338
func (lbaas *LbaasV2) ensureLoadBalancerDeleted(ctx context.Context, clusterName string, service *corev1.Service) error {
22762339
lbName := lbaas.GetLoadBalancerName(ctx, clusterName, service)
22772340
legacyName := lbaas.getLoadBalancerLegacyName(ctx, clusterName, service)
@@ -2336,21 +2399,10 @@ func (lbaas *LbaasV2) ensureLoadBalancerDeleted(ctx context.Context, clusterName
23362399

23372400
// Delete the floating IP only if it was created dynamically by the controller manager.
23382401
if fip != nil {
2339-
klog.InfoS("Matching floating IP", "floatingIP", fip.FloatingIP, "description", fip.Description)
2340-
matched, err := regexp.Match("Floating IP for Kubernetes external service", []byte(fip.Description))
2402+
_, err = lbaas.deleteFIPIfCreatedByProvider(fip, portID, service)
23412403
if err != nil {
23422404
return err
23432405
}
2344-
2345-
if matched {
2346-
klog.InfoS("Deleting floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
2347-
mc := metrics.NewMetricContext("floating_ip", "delete")
2348-
err := floatingips.Delete(lbaas.network, fip.ID).ExtractErr()
2349-
if mc.ObserveRequest(err) != nil {
2350-
return fmt.Errorf("failed to delete floating IP %s for loadbalancer VIP port %s: %v", fip.FloatingIP, portID, err)
2351-
}
2352-
klog.InfoS("Deleted floating IP for service", "floatingIP", fip.FloatingIP, "service", klog.KObj(service))
2353-
}
23542406
}
23552407
}
23562408
}

0 commit comments

Comments
 (0)