@@ -39,12 +39,23 @@ func (m *LBManager) CreateSvcLBIfNone(ctx context.Context, in *api.Postgres) err
39
39
return fmt .Errorf ("failed to fetch Service of type LoadBalancer: %w" , err )
40
40
}
41
41
42
- nextFreePort , err := m .nextFreePort (ctx )
42
+ existingLBIP , nextFreePort , err := m .nextFreeSocket (ctx )
43
43
if err != nil {
44
- return fmt .Errorf ("failed to get the next free port: %w" , err )
44
+ return fmt .Errorf ("failed to get a free port for creating Service of type LoadBalancer: %w" , err )
45
+ }
46
+ var lbIPToUse string
47
+ if m .LBIP != "" {
48
+ // a specific IP was configured in the config, so use that one
49
+ lbIPToUse = m .LBIP
50
+ } else if existingLBIP != "" {
51
+ // no ip was configured, but one is already in use, so use the existing one
52
+ lbIPToUse = existingLBIP
53
+ } else {
54
+ // nothing was configured, nothing exists yet, so use an empty address so a new loadbalancer will be created and assigned
55
+ lbIPToUse = ""
45
56
}
46
57
47
- if err := m .Create (ctx , in .ToSvcLB (m . LBIP , nextFreePort )); err != nil {
58
+ if err := m .Create (ctx , in .ToSvcLB (lbIPToUse , nextFreePort )); err != nil {
48
59
return fmt .Errorf ("failed to create Service of type LoadBalancer: %w" , err )
49
60
}
50
61
return nil
@@ -64,27 +75,35 @@ func (m *LBManager) DeleteSvcLB(ctx context.Context, in *api.Postgres) error {
64
75
}
65
76
66
77
// nextFreeSocket finds any existing LoadBalancerIP and the next free port out of the configure port range.
67
- func (m * LBManager ) nextFreePort (ctx context.Context ) (int32 , error ) {
78
+ func (m * LBManager ) nextFreeSocket (ctx context.Context ) (string , int32 , error ) {
68
79
// TODO prevent concurrency issues when calculating port / ip.
69
80
81
+ anyExistingLBIP := ""
82
+
70
83
// Fetch all services managed by this postgreslet
71
84
lbs := & corev1.ServiceList {}
72
85
if err := m .List (ctx , lbs , client .MatchingLabels (api .SvcLoadBalancerLabel )); err != nil {
73
- return 0 , fmt .Errorf ("failed to fetch the list of services of type LoadBalancer: %w" , err )
86
+ return anyExistingLBIP , 0 , fmt .Errorf ("failed to fetch the list of services of type LoadBalancer: %w" , err )
74
87
}
75
88
76
89
// If there are none, this will be the first (managed) service we create, so start with PortRangeStart and return
77
90
if len (lbs .Items ) == 0 {
78
- return m .PortRangeStart , nil
91
+ return anyExistingLBIP , m .PortRangeStart , nil
79
92
}
80
93
81
94
// If there are already any managed services, store all the used ports in a slice.
82
- portsInUse := []int32 {}
95
+ // Also store the LoadBalancerIP.
96
+ portsInUse := make ([]int32 , 0 , len (lbs .Items ))
83
97
for i := range lbs .Items {
84
98
svc := lbs .Items [i ]
85
99
if len (svc .Spec .Ports ) > 0 {
86
100
portsInUse = append (portsInUse , svc .Spec .Ports [0 ].Port )
87
101
}
102
+ if svc .Spec .LoadBalancerIP != "" {
103
+ // Technically, we only store the IP of the last Service in this list.
104
+ // As there should only be one IP per postgreslet and one postgreslet per cluster, this is good enough.
105
+ anyExistingLBIP = svc .Spec .LoadBalancerIP
106
+ }
88
107
}
89
108
90
109
// Now try all ports in the configured port range to find a free one.
@@ -96,11 +115,11 @@ func (m *LBManager) nextFreePort(ctx context.Context) (int32, error) {
96
115
continue
97
116
}
98
117
// The postgreslet hasn't assigned this port yet, so use it.
99
- return port , nil
118
+ return anyExistingLBIP , port , nil
100
119
}
101
120
102
121
// If we made it this far, no free port could be found.
103
- return 0 , errors .New ("no free port in the configured port range found" )
122
+ return anyExistingLBIP , 0 , errors .New ("no free port in the configured port range found" )
104
123
}
105
124
106
125
func containsElem (s []int32 , v int32 ) bool {
0 commit comments