@@ -20,12 +20,14 @@ import (
20
20
"context"
21
21
"errors"
22
22
"fmt"
23
+ "time"
23
24
24
25
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external"
25
26
corev1 "k8s.io/api/core/v1"
26
27
apierrors "k8s.io/apimachinery/pkg/api/errors"
27
28
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
29
"k8s.io/apimachinery/pkg/runtime"
30
+ "k8s.io/apimachinery/pkg/util/wait"
29
31
"k8s.io/client-go/tools/record"
30
32
"k8s.io/utils/pointer"
31
33
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -47,6 +49,15 @@ const (
47
49
openStackFloatingIPPool = "OpenStackFloatingIPPool"
48
50
)
49
51
52
+ var (
53
+ backoff = wait.Backoff {
54
+ Steps : 4 ,
55
+ Duration : 10 * time .Millisecond ,
56
+ Factor : 5.0 ,
57
+ Jitter : 0.1 ,
58
+ }
59
+ )
60
+
50
61
// OpenStackFloatingIPPoolReconciler reconciles a OpenStackFloatingIPPool object.
51
62
type OpenStackFloatingIPPoolReconciler struct {
52
63
Client client.Client
@@ -158,7 +169,16 @@ func (r *OpenStackFloatingIPPoolReconciler) Reconcile(ctx context.Context, req c
158
169
},
159
170
}
160
171
161
- if err = r .Client .Create (ctx , ipAddress ); err != nil {
172
+ // Retry creating the IPAddress object
173
+ err = wait .ExponentialBackoff (backoff , func () (bool , error ) {
174
+ if err := r .Client .Create (ctx , ipAddress ); err != nil {
175
+ return false , nil
176
+ }
177
+ return true , nil
178
+ })
179
+ if err != nil {
180
+ // If we failed to create the IPAddress, there might be an IP leak in OpenStack if we also failed to tag the IP after creation
181
+ scope .Logger ().Error (err , "Failed to create IPAddress" , "ip" , ip )
162
182
return ctrl.Result {}, err
163
183
}
164
184
} else {
@@ -283,6 +303,7 @@ func (r *OpenStackFloatingIPPoolReconciler) reconcileIPAddresses(ctx context.Con
283
303
}
284
304
285
305
func (r * OpenStackFloatingIPPoolReconciler ) getIP (scope scope.Scope , pool * infrav1.OpenStackFloatingIPPool ) (string , error ) {
306
+ // There's a potential leak of IPs here, if the reconcile loop fails after we claim an IP but before we create the IPAddress object.
286
307
var ip string
287
308
288
309
networkingService , err := networking .NewService (scope )
@@ -291,6 +312,21 @@ func (r *OpenStackFloatingIPPoolReconciler) getIP(scope scope.Scope, pool *infra
291
312
return "" , err
292
313
}
293
314
315
+ // Get tagged floating IPs and add them to the available IPs if they are not present in either the available IPs or the claimed IPs
316
+ // This is done to prevent leaking floating IPs if to prevent leaking floating IPs if the floating IP was created but the IPAddress object was not
317
+ taggedFIPs , err := networkingService .GetFloatingIPsByTag (pool .GetFloatingIPTag ())
318
+ if err != nil {
319
+ scope .Logger ().Error (err , "Failed to get floating IPs by tag" , "pool" , pool .Name )
320
+ return "" , err
321
+ }
322
+ for _ , taggedIp := range taggedFIPs {
323
+ if contains (pool .Status .AvailableIPs , taggedIp .FloatingIP ) || contains (pool .Status .ClaimedIPs , taggedIp .FloatingIP ) {
324
+ continue
325
+ }
326
+ scope .Logger ().Info ("Tagged floating IP found that was not known to the pool, adding it to the pool" , "ip" , taggedIp .FloatingIP )
327
+ pool .Status .AvailableIPs = append (pool .Status .AvailableIPs , taggedIp .FloatingIP )
328
+ }
329
+
294
330
if len (pool .Status .AvailableIPs ) > 0 {
295
331
ip = pool .Status .AvailableIPs [0 ]
296
332
pool .Status .AvailableIPs = pool .Status .AvailableIPs [1 :]
@@ -315,6 +351,22 @@ func (r *OpenStackFloatingIPPoolReconciler) getIP(scope scope.Scope, pool *infra
315
351
}
316
352
return "" , err
317
353
}
354
+ defer func () {
355
+ tag := pool .GetFloatingIPTag ()
356
+
357
+ err := wait .ExponentialBackoff (backoff , func () (bool , error ) {
358
+ if err := networkingService .TagFloatingIP (fp .FloatingIP , tag ); err != nil {
359
+ scope .Logger ().Error (err , "Failed to tag floating, retrying" , "ip" , fp .FloatingIP , "tag" , tag )
360
+ return false , err
361
+ }
362
+ return true , nil
363
+ })
364
+
365
+ if err != nil {
366
+ scope .Logger ().Error (err , "Failed to tag floating IP" , "ip" , fp .FloatingIP , "tag" , tag )
367
+ }
368
+ }()
369
+
318
370
conditions .MarkTrue (pool , infrav1 .OpenstackFloatingIPPoolReadyCondition )
319
371
320
372
ip = fp .FloatingIP
0 commit comments