diff options
author | Miloslav Trmač <mitr@redhat.com> | 2021-11-19 10:01:02 +0100 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2021-11-30 22:13:52 +0100 |
commit | f415b3055290b383c76d98127ec168ddea629680 (patch) | |
tree | b43793cbf686389fc6c079e03b6b0486cd769baf | |
parent | a948ecbb9c7c90e249cded94a2239192a4ad766a (diff) | |
download | podman-f415b3055290b383c76d98127ec168ddea629680.tar.gz podman-f415b3055290b383c76d98127ec168ddea629680.tar.bz2 podman-f415b3055290b383c76d98127ec168ddea629680.zip |
Ensure the generated NodePort values are unique
... 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č <mitr@redhat.com>
-rw-r--r-- | libpod/kube.go | 22 |
1 files changed, 18 insertions, 4 deletions
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, |