Skip to content

Commit 0f8ebb2

Browse files
[CAE-342] Using cae containers for sentinel
1 parent 07b7cdf commit 0f8ebb2

File tree

2 files changed

+66
-26
lines changed

2 files changed

+66
-26
lines changed

packages/test-utils/lib/dockers.ts

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { setTimeout } from 'node:timers/promises';
66
// import { ClusterSlotsReply } from '@redis/client/dist/lib/commands/CLUSTER_SLOTS';
77
import { execFile as execFileCallback } from 'node:child_process';
88
import { promisify } from 'node:util';
9+
import * as fs from 'node:fs';
10+
import * as os from 'node:os';
11+
import * as path from 'node:path';
912

1013
const execAsync = promisify(execFileCallback);
1114

@@ -37,21 +40,37 @@ const portIterator = (async function* (): AsyncIterableIterator<number> {
3740
throw new Error('All ports are in use');
3841
})();
3942

40-
export interface RedisServerDockerConfig {
43+
interface RedisServerDockerConfig {
4144
image: string;
4245
version: string;
4346
}
4447

48+
interface SentinelConfig {
49+
mode: "sentinel";
50+
mounts: Array<string>;
51+
port: number;
52+
}
53+
54+
interface ServerConfig {
55+
mode: "server";
56+
}
57+
58+
export type RedisServerDockerOptions = RedisServerDockerConfig & (SentinelConfig | ServerConfig)
59+
4560
export interface RedisServerDocker {
4661
port: number;
4762
dockerId: string;
4863
}
4964

50-
async function spawnRedisServerDocker({
51-
image,
52-
version
53-
}: RedisServerDockerConfig, serverArguments: Array<string>, dockerEnv?: Map<string, string>): Promise<RedisServerDocker> {
54-
const port = (await portIterator.next()).value;
65+
async function spawnRedisServerDocker(
66+
options: RedisServerDockerOptions, serverArguments: Array<string>, dockerEnv?: Map<string, string>): Promise<RedisServerDocker> {
67+
let port;
68+
if (options.mode == "sentinel") {
69+
port = options.port;
70+
} else {
71+
port = (await portIterator.next()).value;
72+
}
73+
5574
const portStr = port.toString();
5675

5776
const dockerArgs = [
@@ -60,23 +79,29 @@ async function spawnRedisServerDocker({
6079
'-e', `PORT=${portStr}`
6180
];
6281

82+
if (options.mode == "sentinel") {
83+
options.mounts.forEach(mount => {
84+
dockerArgs.push('-v', mount);
85+
});
86+
}
87+
6388
dockerEnv?.forEach((key: string, value: string) => {
6489
dockerArgs.push('-e', `${key}:${value}`);
6590
});
6691

6792
dockerArgs.push(
6893
'-d',
6994
'--network', 'host',
70-
`${image}:${version}`
95+
`${options.image}:${options.version}`
7196
);
7297

7398
if (serverArguments.length > 0) {
7499
for (let i = 0; i < serverArguments.length; i++) {
75-
dockerArgs.push(serverArguments[i].replace('{port}', `${portStr}`))
100+
dockerArgs.push(serverArguments[i])
76101
}
77102
}
78103

79-
console.log(`[Docker] Spawning Redis container - Image: ${image}:${version}, Port: ${port}`);
104+
console.log(`[Docker] Spawning Redis container - Image: ${options.image}:${options.version}, Port: ${port}, Mode: ${options.mode}`);
80105

81106
const { stdout, stderr } = await execAsync('docker', dockerArgs);
82107

@@ -95,7 +120,7 @@ async function spawnRedisServerDocker({
95120
}
96121
const RUNNING_SERVERS = new Map<Array<string>, ReturnType<typeof spawnRedisServerDocker>>();
97122

98-
export function spawnRedisServer(dockerConfig: RedisServerDockerConfig, serverArguments: Array<string>): Promise<RedisServerDocker> {
123+
export function spawnRedisServer(dockerConfig: RedisServerDockerOptions, serverArguments: Array<string>): Promise<RedisServerDocker> {
99124
const runningServer = RUNNING_SERVERS.get(serverArguments);
100125
if (runningServer) {
101126
return runningServer;
@@ -121,7 +146,7 @@ after(() => {
121146
);
122147
});
123148

124-
export interface RedisClusterDockersConfig extends RedisServerDockerConfig {
149+
export type RedisClusterDockersConfig = RedisServerDockerOptions & {
125150
numberOfMasters?: number;
126151
numberOfReplicas?: number;
127152
}
@@ -186,7 +211,7 @@ async function spawnRedisClusterNodeDockers(
186211
}
187212

188213
async function spawnRedisClusterNodeDocker(
189-
dockersConfig: RedisClusterDockersConfig,
214+
dockersConfig: RedisServerDockerOptions,
190215
serverArguments: Array<string>,
191216
clientConfig?: Partial<RedisClusterClientOptions>
192217
) {
@@ -305,7 +330,7 @@ const RUNNING_NODES = new Map<Array<string>, Array<RedisServerDocker>>();
305330
const RUNNING_SENTINELS = new Map<Array<string>, Array<RedisServerDocker>>();
306331

307332
export async function spawnRedisSentinel(
308-
dockerConfigs: RedisServerDockerConfig,
333+
dockerConfigs: RedisServerDockerOptions,
309334
serverArguments: Array<string>,
310335
password?: string,
311336
): Promise<Array<RedisServerDocker>> {
@@ -351,33 +376,47 @@ export async function spawnRedisSentinel(
351376
const sentinelPromises: Array<Promise<RedisServerDocker>> = [];
352377
const sentinelCount = 3;
353378

379+
const appPrefix = 'sentinel-config-dir';
380+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), appPrefix));
381+
354382
for (let i = 0; i < sentinelCount; i++) {
355383
sentinelPromises.push((async () => {
356-
const sentinelArgs: Array<string> = ["sh", "-c"];
357-
358-
let sentinelConfig = `
359-
port {port}
384+
const port = (await portIterator.next()).value;
385+
386+
let sentinelConfig = `port ${port}
360387
sentinel monitor mymaster 127.0.0.1 ${master.port} 2
361388
sentinel down-after-milliseconds mymaster 5000
362389
sentinel failover-timeout mymaster 6000
363390
`;
364391
if (password !== undefined) {
365-
sentinelConfig += `requirepass ${password}\n`
366-
sentinelConfig += `sentinel auth-pass mymaster ${password}\n`
392+
sentinelConfig += `requirepass ${password}\n`;
393+
sentinelConfig += `sentinel auth-pass mymaster ${password}\n`;
367394
}
368395

369-
sentinelArgs.push(`echo "${sentinelConfig}" > /tmp/sentinel.conf && redis-sentinel /tmp/sentinel.conf`);
370-
return await spawnRedisServerDocker({image: "redis", version: "latest"}, sentinelArgs);
396+
const dir = fs.mkdtempSync(path.join(tmpDir, i.toString()));
397+
fs.writeFile(`${dir}/redis.conf`, sentinelConfig, err => {});
398+
399+
return await spawnRedisServerDocker(
400+
{
401+
image: dockerConfigs.image,
402+
version: dockerConfigs.version,
403+
mode: "sentinel",
404+
mounts: [`${dir}/redis.conf:/redis/config/node-sentinel-1/redis.conf`],
405+
port: port,
406+
}, serverArguments, dockerEnv);
371407
})());
372408
}
373409

374410
const sentinelNodes = await Promise.all(sentinelPromises);
375411
RUNNING_SENTINELS.set(serverArguments, sentinelNodes);
376412

413+
if (tmpDir) {
414+
fs.rmSync(tmpDir, { recursive: true });
415+
}
416+
377417
return sentinelNodes;
378418
}
379419

380-
381420
after(() => {
382421
return Promise.all(
383422
[...RUNNING_NODES.values(), ...RUNNING_SENTINELS.values()].map(async dockersPromise => {
@@ -386,4 +425,4 @@ after(() => {
386425
);
387426
})
388427
);
389-
});
428+
});

packages/test-utils/lib/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
RedisClusterType
2020
} from '@redis/client/index';
2121
import { RedisNode } from '@redis/client/lib/sentinel/types'
22-
import { RedisServerDockerConfig, spawnRedisServer, spawnRedisCluster, spawnRedisSentinel } from './dockers';
22+
import { spawnRedisServer, spawnRedisCluster, spawnRedisSentinel, RedisServerDockerOptions } from './dockers';
2323
import yargs from 'yargs';
2424
import { hideBin } from 'yargs/helpers';
2525

@@ -171,13 +171,14 @@ export default class TestUtils {
171171
}
172172

173173
readonly #VERSION_NUMBERS: Array<number>;
174-
readonly #DOCKER_IMAGE: RedisServerDockerConfig;
174+
readonly #DOCKER_IMAGE: RedisServerDockerOptions;
175175

176176
constructor({ string, numbers }: Version, dockerImageName: string) {
177177
this.#VERSION_NUMBERS = numbers;
178178
this.#DOCKER_IMAGE = {
179179
image: dockerImageName,
180-
version: string
180+
version: string,
181+
mode: "server"
181182
};
182183
}
183184

0 commit comments

Comments
 (0)