From f415b3055290b383c76d98127ec168ddea629680 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 19 Nov 2021 10:01:02 +0100 Subject: Ensure the generated NodePort values are unique MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... at least within a single service. [NO NEW TESTS NEEDED] because testing RNGs is problematic. (We _could_ probably inject a mock RNG implementation that always returns the same value, or something like that.) Signed-off-by: Miloslav Trmač --- libpod/kube.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'libpod') diff --git a/libpod/kube.go b/libpod/kube.go index bdd5b9a4f..4e61b5377 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -277,12 +277,14 @@ func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) (Y type servicePortState struct { // A program using the shared math/rand state with the default seed will produce the same sequence of pseudo-random numbers // for each execution. Use a private RNG state not to interfere with other users. - rng *rand.Rand + rng *rand.Rand + usedPorts map[int]struct{} } func newServicePortState() servicePortState { return servicePortState{ - rng: rand.New(rand.NewSource(time.Now().UnixNano())), + rng: rand.New(rand.NewSource(time.Now().UnixNano())), + usedPorts: map[int]struct{}{}, } } @@ -291,8 +293,20 @@ func newServicePortState() servicePortState { func (state *servicePortState) containerPortsToServicePorts(containerPorts []v1.ContainerPort) ([]v1.ServicePort, error) { sps := make([]v1.ServicePort, 0, len(containerPorts)) for _, cp := range containerPorts { - // Legal nodeport range is 30000-32767 - nodePort := 30000 + state.rng.Intn(32767-30000+1) + var nodePort int + attempt := 0 + for { + // Legal nodeport range is 30000-32767 + nodePort = 30000 + state.rng.Intn(32767-30000+1) + if _, found := state.usedPorts[nodePort]; !found { + state.usedPorts[nodePort] = struct{}{} + break + } + attempt++ + if attempt >= 100 { + return nil, fmt.Errorf("too many attempts trying to generate a unique NodePort number") + } + } servicePort := v1.ServicePort{ Protocol: cp.Protocol, Port: cp.ContainerPort, -- cgit v1.2.3-54-g00ecf