diff options
author | Miloslav Trmač <mitr@redhat.com> | 2021-11-19 10:01:02 +0100 |
---|---|---|
committer | Matthew Heon <mheon@redhat.com> | 2021-12-06 15:48:51 -0500 |
commit | 7dbe5508bb60ce530efd41fdfb0967f6c436a3b7 (patch) | |
tree | 2fe467b4841994ac670e98dee78e5a1174669b5f | |
parent | bb1293133d18c95223362e6202e4eee967ab43e4 (diff) | |
download | podman-7dbe5508bb60ce530efd41fdfb0967f6c436a3b7.tar.gz podman-7dbe5508bb60ce530efd41fdfb0967f6c436a3b7.tar.bz2 podman-7dbe5508bb60ce530efd41fdfb0967f6c436a3b7.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 29f01c6c5..12d1c5be8 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -276,12 +276,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{}{}, } } @@ -290,8 +292,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, |