mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core): Add a new option to customize SSH tunnel idle timeout (#14522)
This commit is contained in:
committed by
GitHub
parent
78f00f2e3a
commit
965baae093
@@ -1,9 +1,11 @@
|
|||||||
|
import { mock } from 'jest-mock-extended';
|
||||||
import type { SSHCredentials } from 'n8n-workflow';
|
import type { SSHCredentials } from 'n8n-workflow';
|
||||||
import { Client } from 'ssh2';
|
import { Client } from 'ssh2';
|
||||||
|
|
||||||
import { SSHClientsManager } from '../ssh-clients-manager';
|
import { SSHClientsManager } from '../ssh-clients-manager';
|
||||||
|
|
||||||
describe('SSHClientsManager', () => {
|
describe('SSHClientsManager', () => {
|
||||||
|
const idleTimeout = 5 * 60;
|
||||||
const credentials: SSHCredentials = {
|
const credentials: SSHCredentials = {
|
||||||
sshAuthenticateWith: 'password',
|
sshAuthenticateWith: 'password',
|
||||||
sshHost: 'example.com',
|
sshHost: 'example.com',
|
||||||
@@ -20,7 +22,7 @@ describe('SSHClientsManager', () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
|
||||||
sshClientsManager = new SSHClientsManager();
|
sshClientsManager = new SSHClientsManager(mock({ idleTimeout }));
|
||||||
connectSpy.mockImplementation(function (this: Client) {
|
connectSpy.mockImplementation(function (this: Client) {
|
||||||
this.emit('ready');
|
this.emit('ready');
|
||||||
return this;
|
return this;
|
||||||
@@ -59,7 +61,7 @@ describe('SSHClientsManager', () => {
|
|||||||
await sshClientsManager.getClient({ ...credentials, sshHost: 'host2' });
|
await sshClientsManager.getClient({ ...credentials, sshHost: 'host2' });
|
||||||
await sshClientsManager.getClient({ ...credentials, sshHost: 'host3' });
|
await sshClientsManager.getClient({ ...credentials, sshHost: 'host3' });
|
||||||
|
|
||||||
jest.advanceTimersByTime(6 * 60 * 1000);
|
jest.advanceTimersByTime((idleTimeout + 1) * 1000);
|
||||||
sshClientsManager.cleanupStaleConnections();
|
sshClientsManager.cleanupStaleConnections();
|
||||||
|
|
||||||
expect(endSpy).toHaveBeenCalledTimes(3);
|
expect(endSpy).toHaveBeenCalledTimes(3);
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
|
import { Config, Env } from '@n8n/config';
|
||||||
import { Service } from '@n8n/di';
|
import { Service } from '@n8n/di';
|
||||||
import type { SSHCredentials } from 'n8n-workflow';
|
import type { SSHCredentials } from 'n8n-workflow';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { Client, type ConnectConfig } from 'ssh2';
|
import { Client, type ConnectConfig } from 'ssh2';
|
||||||
|
|
||||||
|
@Config
|
||||||
|
class SSHClientsConfig {
|
||||||
|
/** How many seconds before an idle SSH tunnel is closed */
|
||||||
|
@Env('N8N_SSH_TUNNEL_IDLE_TIMEOUT')
|
||||||
|
idleTimeout: number = 5 * 60;
|
||||||
|
}
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class SSHClientsManager {
|
export class SSHClientsManager {
|
||||||
readonly clients = new Map<string, { client: Client; lastUsed: Date }>();
|
readonly clients = new Map<string, { client: Client; lastUsed: Date }>();
|
||||||
|
|
||||||
constructor() {
|
constructor(private readonly config: SSHClientsConfig) {
|
||||||
// Close all SSH connections when the process exits
|
// Close all SSH connections when the process exits
|
||||||
process.on('exit', () => this.onShutdown());
|
process.on('exit', () => this.onShutdown());
|
||||||
|
|
||||||
@@ -67,7 +75,7 @@ export class SSHClientsManager {
|
|||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
for (const [hash, { client, lastUsed }] of clients.entries()) {
|
for (const [hash, { client, lastUsed }] of clients.entries()) {
|
||||||
if (now - lastUsed.getTime() > 5 * 60 * 1000) {
|
if (now - lastUsed.getTime() > this.config.idleTimeout * 1000) {
|
||||||
client.end();
|
client.end();
|
||||||
clients.delete(hash);
|
clients.delete(hash);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user