mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix port availability test (#333)
* Let OS allocate port number Port availability might be tricky if some port is already in use on the 'all' interface '0.0.0.0'. The proposed solution is to let the OS allocate the port for us using 0 as port specifier : - first create a server instance to allocate a port number - save port number - close the server - return the port number to the caller This should be safe granted the OS doesn't reuse the port numbers on consecutive port allocations. see : - about Node.js Net module : https://nodejs.org/docs/latest-v12.x/api/net.html#net_server_listen_port_host_backlog_callback - about safety around reusing port number : https://unix.stackexchange.com/a/132524 Signed-off-by: Alexis Deruelle <alexis.deruelle@gmail.com>
This commit is contained in:
parent
0a3b5dae73
commit
6412d73a5a
@ -2,13 +2,10 @@ import { EventEmitter } from 'events'
|
|||||||
|
|
||||||
class MockServer extends EventEmitter {
|
class MockServer extends EventEmitter {
|
||||||
listen = jest.fn((obj) => {
|
listen = jest.fn((obj) => {
|
||||||
if(obj.port < 9003) {
|
|
||||||
this.emit('error', new Error("fail!"))
|
|
||||||
} else {
|
|
||||||
this.emit('listening', {})
|
this.emit('listening', {})
|
||||||
}
|
|
||||||
return this
|
return this
|
||||||
})
|
})
|
||||||
|
address = () => { return { port: 12345 }}
|
||||||
unref = jest.fn()
|
unref = jest.fn()
|
||||||
close = jest.fn((cb) => {
|
close = jest.fn((cb) => {
|
||||||
cb()
|
cb()
|
||||||
@ -29,11 +26,7 @@ describe("getFreePort", () => {
|
|||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("fails for an invalid range", async () => {
|
|
||||||
return expect(port.getFreePort(1, 2)).rejects.toMatch('free port')
|
|
||||||
})
|
|
||||||
|
|
||||||
it("finds the next free port", async () => {
|
it("finds the next free port", async () => {
|
||||||
return expect(port.getFreePort(9000, 9005)).resolves.toBe(9003)
|
return expect(port.getFreePort()).resolves.toEqual(expect.any(Number))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -135,7 +135,7 @@ export class ContextHandler {
|
|||||||
|
|
||||||
let serverPort: number = null
|
let serverPort: number = null
|
||||||
try {
|
try {
|
||||||
serverPort = await getFreePort(49901, 65535)
|
serverPort = await getFreePort()
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
throw(error)
|
throw(error)
|
||||||
|
|||||||
@ -48,7 +48,7 @@ async function main() {
|
|||||||
let port: number = null
|
let port: number = null
|
||||||
// find free port
|
// find free port
|
||||||
try {
|
try {
|
||||||
port = await getFreePort(49152, 65535)
|
port = await getFreePort()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy")
|
await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy")
|
||||||
|
|||||||
@ -1,27 +1,30 @@
|
|||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import { createServer } from "net"
|
import { createServer } from "net"
|
||||||
|
import { AddressInfo } from "net"
|
||||||
|
|
||||||
// Adapted from https://gist.github.com/mikeal/1840641#gistcomment-2896667
|
const getNextAvailablePort = () => {
|
||||||
function checkPort(port: number) {
|
logger.debug("getNextAvailablePort() start")
|
||||||
const server = createServer()
|
const server = createServer()
|
||||||
server.unref()
|
server.unref()
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise<number>((resolve, reject) =>
|
||||||
server
|
server
|
||||||
.on('error', error => reject(error))
|
.on('error', (error: any) => reject(error))
|
||||||
.on('listening', () => server.close(() => resolve(port)))
|
.on('listening', () => {
|
||||||
.listen({host: "127.0.0.1", port: port}))
|
logger.debug("*** server listening event ***")
|
||||||
|
const _port = (server.address() as AddressInfo).port
|
||||||
|
server.close(() => resolve(_port))
|
||||||
|
})
|
||||||
|
.listen({host: "127.0.0.1", port: 0}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getFreePort(firstPort: number, lastPort: number): Promise<number> {
|
export const getFreePort = async () => {
|
||||||
let port = firstPort
|
logger.debug("getFreePort() start")
|
||||||
|
let freePort: number = null
|
||||||
while(true) {
|
|
||||||
try {
|
try {
|
||||||
logger.debug("Checking port " + port + " availability ...")
|
freePort = await getNextAvailablePort()
|
||||||
await checkPort(port)
|
logger.debug("got port : " + freePort)
|
||||||
return(port)
|
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
if(++port > lastPort) throw("Could not find a free port")
|
throw("getNextAvailablePort() threw: '" + error + "'")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return freePort
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class PortForward {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
this.localPort = await getFreePort(8000, 9999)
|
this.localPort = await getFreePort()
|
||||||
const kubectlBin = await bundledKubectl.kubectlPath()
|
const kubectlBin = await bundledKubectl.kubectlPath()
|
||||||
const args = [
|
const args = [
|
||||||
"--kubeconfig", this.kubeConfig,
|
"--kubeconfig", this.kubeConfig,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user