5

I am currently working on improving my Jenkins Pipeline, which starts a docker container with an exposed port. But due to the fact, that the Jenkins instance is heavily used by many people and their projects, I have run into the problem, that the exposed port mapping is already in use.

My idea is to determine an unused port on the host machine, to circumvent this problem. In order to do this, I want to expand our Jenkins shared the library with a simple method to check and return the first unused port from the host system.

Has anyone an idea how to achieve this?

My current solution would be to utilize a shell function which somehow uses the netstat tool.

File: getRandomFreePort.groovy

def call() {
sh '''
    #!/bin/bash
    while
    [[!-z $CHECK]]; do
    PORT = $(((RANDOM % 60000) + 1025))
    CHECK = $(sudo netstat - ap | grep $PORT)
    done

    echo $PORT
'''
}
Kaval Patel
  • 670
  • 4
  • 20
onkeliroh
  • 1,530
  • 1
  • 14
  • 25
  • The [plugin that's supposed to do this](https://plugins.jenkins.io/port-allocator) still doesn't support pipelines :( – OrangeDog Feb 27 '19 at 18:20

3 Answers3

4

Using ServerSocket you can get a unused port with this command:

try {
    def serverSocket = new ServerSocket(0);
    System.out.println("listening on port: " + serverSocket.getLocalPort());
    //Do anything
    serverSocket.close()
} catch (IOException ex) {
    System.err.println("no available ports");
}

If you need to found an available port in a range, check this post: How to find an available port in a range?

Javier C.
  • 7,859
  • 5
  • 41
  • 53
2

An easy one-liner:

def port = new ServerSocket(0).withCloseable { socket -> socket.getLocalPort() }

Creating a socket bound to 0 allocates an arbitrary free port.

Note that will require script approval if security is enabled.

There's also no reservation mechanism, so while it was free when it was assigned to the socket, it's possible that something else will take it after this code has run.

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
1

I spend a lot of the time looking for the possibility to do it without approval. And found it, using Python inside of Groovy.

String port = sh(script: 'echo $(python -c \'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()\');', returnStdout: true)

The solution looks not very clean but works well.

Den
  • 81
  • 1
  • 2
  • works well without specific authorization and `socket` is included in `python`. For formatting it'll be easier to read like this: ````groovy sh ( script: """ echo \$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') """, returnStdout: true ).trim() ``` – Thomas Dec 28 '21 at 13:23