@@ -908,26 +908,74 @@ func (lbaas *LbaasV2) createFloatingIP(msg string, floatIPOpts floatingips.Creat
908
908
return floatIP , err
909
909
}
910
910
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 ,
919
914
}
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 ) {
922
942
serviceName := fmt .Sprintf ("%s/%s" , service .Namespace , service .Name )
923
943
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
925
945
portID := lb .VipPortID
926
946
floatIP , err := openstackutil .GetFloatingIPByPortID (lbaas .network , portID )
927
947
if err != nil {
928
948
return "" , fmt .Errorf ("failed when getting floating IP for port %s: %v" , portID , err )
929
949
}
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.
931
979
932
980
// we cannot add a FIP to a shared LB when we're a secondary Service or we risk adding it to an internal
933
981
// Service and exposing it to the world unintentionally.
@@ -952,14 +1000,9 @@ func (lbaas *LbaasV2) getServiceAddress(clusterName string, service *corev1.Serv
952
1000
if len (existingIPs ) > 0 {
953
1001
floatingip := existingIPs [0 ]
954
1002
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
963
1006
}
964
1007
} else {
965
1008
return "" , fmt .Errorf ("floating IP %s is not available" , loadBalancerIP )
@@ -1973,7 +2016,7 @@ func (lbaas *LbaasV2) ensureOctaviaLoadBalancer(ctx context.Context, clusterName
1973
2016
}
1974
2017
}
1975
2018
1976
- addr , err := lbaas .getServiceAddress (clusterName , service , loadbalancer , svcConf , isLBOwner )
2019
+ addr , err := lbaas .ensureFloatingIP (clusterName , service , loadbalancer , svcConf , isLBOwner )
1977
2020
if err != nil {
1978
2021
return nil , err
1979
2022
}
@@ -2272,6 +2315,26 @@ func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(ctx context.Context, clusterName
2272
2315
return mc .ObserveReconcile (err )
2273
2316
}
2274
2317
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
+
2275
2338
func (lbaas * LbaasV2 ) ensureLoadBalancerDeleted (ctx context.Context , clusterName string , service * corev1.Service ) error {
2276
2339
lbName := lbaas .GetLoadBalancerName (ctx , clusterName , service )
2277
2340
legacyName := lbaas .getLoadBalancerLegacyName (ctx , clusterName , service )
@@ -2336,21 +2399,10 @@ func (lbaas *LbaasV2) ensureLoadBalancerDeleted(ctx context.Context, clusterName
2336
2399
2337
2400
// Delete the floating IP only if it was created dynamically by the controller manager.
2338
2401
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 )
2341
2403
if err != nil {
2342
2404
return err
2343
2405
}
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
- }
2354
2406
}
2355
2407
}
2356
2408
}
0 commit comments