Skip to content

Commit 25c7e89

Browse files
committed
Refactor the implementation of nextFreePort
1 parent 3d894f0 commit 25c7e89

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

pkg/lbmanager/lbmanager.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import (
1111
"sigs.k8s.io/controller-runtime/pkg/client"
1212
)
1313

14+
// LBManager Responsible for the creation and deletion of externally accessible Services to access the Postgresql clusters managed by the Postgreslet.
1415
type LBManager struct {
15-
client.Client // todo: service cluster
16-
LBIP string // todo: via configmap
17-
PortRangeStart int32 // todo: via configmap
16+
client.Client
17+
LBIP string
18+
PortRangeStart int32
1819
PortRangeSize int32
1920
}
2021

22+
// New Creates a new LBManager with the given configuration
2123
func New(client client.Client, lbIP string, portRangeStart, portRangeSize int32) *LBManager {
2224
return &LBManager{
2325
Client: client,
@@ -27,6 +29,7 @@ func New(client client.Client, lbIP string, portRangeStart, portRangeSize int32)
2729
}
2830
}
2931

32+
// CreateSvcLBIfNone Creates a new Service of type LoadBalancer for the given Postgres resource if neccessary
3033
func (m *LBManager) CreateSvcLBIfNone(ctx context.Context, in *api.Postgres) error {
3134
if err := m.Get(ctx, client.ObjectKey{
3235
Namespace: in.ToPeripheralResourceNamespace(),
@@ -60,6 +63,7 @@ func (m *LBManager) CreateSvcLBIfNone(ctx context.Context, in *api.Postgres) err
6063
return nil
6164
}
6265

66+
// DeleteSvcLB Deletes the corresponding Service of type LoadBalancer of the given Postgres resource.
6367
func (m *LBManager) DeleteSvcLB(ctx context.Context, in *api.Postgres) error {
6468
lb := &corev1.Service{}
6569
lb.Namespace = in.ToPeripheralResourceNamespace()
@@ -70,37 +74,59 @@ func (m *LBManager) DeleteSvcLB(ctx context.Context, in *api.Postgres) error {
7074
return nil
7175
}
7276

77+
// nextFreeSocket finds any existing LoadBalancerIP and the next free port out of the configure port range.
7378
func (m *LBManager) nextFreeSocket(ctx context.Context) (string, int32, error) {
7479
// TODO prevent concurrency issues when calculating port / ip.
7580

7681
existingLBIP := ""
7782

83+
// Fetch all services managed by this postgreslet
7884
lbs := &corev1.ServiceList{}
7985
if err := m.List(ctx, lbs, client.MatchingLabels(api.SvcLoadBalancerLabel)); err != nil {
8086
return existingLBIP, 0, fmt.Errorf("failed to fetch the list of services of type LoadBalancer: %w", err)
8187
}
8288

89+
// If there are none, this will be the first (managed) service we create, so start with PortRangeStart and return
8390
if len(lbs.Items) == 0 {
8491
return existingLBIP, m.PortRangeStart, nil
8592
}
8693

87-
// Record weather any port is occupied
88-
isOccupied := make([]bool, int(m.PortRangeSize))
94+
// If there are already any managed services, store all the used ports in a slice.
95+
// Also store the LoadBalancerIP.
96+
portsInUse := make([]int32, len(lbs.Items))
8997
for i := range lbs.Items {
9098
svc := lbs.Items[i]
9199
if len(svc.Spec.Ports) > 0 {
92-
isOccupied[svc.Spec.Ports[0].Port-m.PortRangeStart] = true
100+
portsInUse = append(portsInUse, svc.Spec.Ports[0].Port)
93101
}
94102
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.
95105
existingLBIP = svc.Spec.LoadBalancerIP
96106
}
97107
}
98108

99-
for i := range isOccupied {
100-
if !isOccupied[i] {
101-
return existingLBIP, m.PortRangeStart + int32(i), nil
109+
// Now try all ports in the configured port range to find a free one.
110+
// While not as effective as other implementations, this allows us to freely change PortRangeStart and PortRangeSize
111+
// retroactively without breaking the implementation.
112+
for port := m.PortRangeStart; port < m.PortRangeStart+m.PortRangeSize; port++ {
113+
if containsElem(portsInUse, port) {
114+
// Port already in use, try the next one
115+
continue
102116
}
117+
// The postgreslet hasn't assigned this port yet, so use it.
118+
return existingLBIP, port, nil
103119
}
104120

105-
return existingLBIP, 0, errors.New("no free port")
121+
// If we made it this far, no free port could be found.
122+
return existingLBIP, 0, errors.New("no free port in the configured port range found")
123+
}
124+
125+
func containsElem(s []int32, v int32) bool {
126+
for _, elem := range s {
127+
if elem == v {
128+
return true
129+
}
130+
}
131+
return false
106132
}

0 commit comments

Comments
 (0)