Skip to content

Commit 93fe4c5

Browse files
authored
Merge pull request #2194 from RedisInsight/feature/RI-4516_redisstack_conditions
Feature/ri 4516 redisstack conditions
2 parents 1981a61 + f238010 commit 93fe4c5

23 files changed

+181
-100
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class DatabaseRedisServer1686719451753 implements MigrationInterface {
4+
name = 'DatabaseRedisServer1686719451753'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`CREATE TABLE "temporary_database_instance" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "name" varchar NOT NULL, "username" varchar, "password" varchar, "tls" boolean, "verifyServerCert" boolean, "lastConnection" datetime, "caCertId" varchar, "clientCertId" varchar, "connectionType" varchar NOT NULL DEFAULT ('STANDALONE'), "nodes" varchar DEFAULT ('[]'), "nameFromProvider" varchar, "sentinelMasterName" varchar, "sentinelMasterUsername" varchar, "sentinelMasterPassword" varchar, "provider" varchar DEFAULT ('UNKNOWN'), "modules" varchar NOT NULL DEFAULT ('[]'), "db" integer, "encryption" varchar, "tlsServername" varchar, "new" boolean, "ssh" boolean, "timeout" integer, "compressor" varchar NOT NULL DEFAULT ('NONE'), "version" varchar, CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
8+
await queryRunner.query(`INSERT INTO "temporary_database_instance"("id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new", "ssh", "timeout", "compressor") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new", "ssh", "timeout", "compressor" FROM "database_instance"`);
9+
await queryRunner.query(`DROP TABLE "database_instance"`);
10+
await queryRunner.query(`ALTER TABLE "temporary_database_instance" RENAME TO "database_instance"`);
11+
}
12+
13+
public async down(queryRunner: QueryRunner): Promise<void> {
14+
await queryRunner.query(`ALTER TABLE "database_instance" RENAME TO "temporary_database_instance"`);
15+
await queryRunner.query(`CREATE TABLE "database_instance" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "name" varchar NOT NULL, "username" varchar, "password" varchar, "tls" boolean, "verifyServerCert" boolean, "lastConnection" datetime, "caCertId" varchar, "clientCertId" varchar, "connectionType" varchar NOT NULL DEFAULT ('STANDALONE'), "nodes" varchar DEFAULT ('[]'), "nameFromProvider" varchar, "sentinelMasterName" varchar, "sentinelMasterUsername" varchar, "sentinelMasterPassword" varchar, "provider" varchar DEFAULT ('UNKNOWN'), "modules" varchar NOT NULL DEFAULT ('[]'), "db" integer, "encryption" varchar, "tlsServername" varchar, "new" boolean, "ssh" boolean, "timeout" integer, "compressor" varchar NOT NULL DEFAULT ('NONE'), CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
16+
await queryRunner.query(`INSERT INTO "database_instance"("id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new", "ssh", "timeout", "compressor") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new", "ssh", "timeout", "compressor" FROM "temporary_database_instance"`);
17+
await queryRunner.query(`DROP TABLE "temporary_database_instance"`);
18+
}
19+
20+
}

redisinsight/api/migration/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { customTutorials1677135091633 } from './1677135091633-custom-tutorials';
3232
import { databaseRecommendations1681900503586 } from './1681900503586-database-recommendations';
3333
import { databaseRecommendationParams1683006064293 } from './1683006064293-database-recommendation-params';
3434
import { Feature1684931530343 } from './1684931530343-feature';
35+
import { DatabaseRedisServer1686719451753 } from './1686719451753-database-redis-server';
3536

3637
export default [
3738
initialMigration1614164490968,
@@ -68,4 +69,5 @@ export default [
6869
databaseRecommendations1681900503586,
6970
databaseRecommendationParams1683006064293,
7071
Feature1684931530343,
72+
DatabaseRedisServer1686719451753,
7173
];

redisinsight/api/src/__mocks__/databases.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const mockDatabase = Object.assign(new Database(), {
3535
timeout: 30_000,
3636
new: false,
3737
compressor: Compressor.NONE,
38+
version: '7.0',
3839
});
3940

4041
export const mockDatabaseEntity = Object.assign(new DatabaseEntity(), {
@@ -219,6 +220,7 @@ export const mockDatabaseInfoProvider = jest.fn(() => ({
219220
isCluster: jest.fn(),
220221
isSentinel: jest.fn(),
221222
determineDatabaseModules: jest.fn(),
223+
determineDatabaseServer: jest.fn(),
222224
determineSentinelMasterGroups: jest.fn().mockReturnValue([mockSentinelMasterDto]),
223225
determineClusterNodes: jest.fn().mockResolvedValue(mockClusterNodes),
224226
getRedisGeneralInfo: jest.fn().mockResolvedValueOnce(mockRedisGeneralInfo),

redisinsight/api/src/modules/database/database-connection.service.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ describe('DatabaseConnectionService', () => {
3131
let redisConnectionFactory: MockType<RedisConnectionFactory>;
3232
let analytics: MockType<DatabaseAnalytics>;
3333
let recommendationService: MockType<DatabaseRecommendationService>;
34+
let databaseInfoProvider: MockType<DatabaseInfoProvider>;
3435

3536
beforeEach(async () => {
3637
jest.clearAllMocks();
@@ -74,6 +75,7 @@ describe('DatabaseConnectionService', () => {
7475
redisConnectionFactory = await module.get(RedisConnectionFactory);
7576
analytics = await module.get(DatabaseAnalytics);
7677
recommendationService = module.get(DatabaseRecommendationService);
78+
databaseInfoProvider = module.get(DatabaseInfoProvider);
7779
});
7880

7981
describe('connect', () => {
@@ -103,6 +105,13 @@ describe('DatabaseConnectionService', () => {
103105
mockRedisGeneralInfo,
104106
);
105107
});
108+
109+
it('should call databaseInfoProvider', async () => {
110+
expect(await service.connect(mockCommonClientMetadata)).toEqual(undefined);
111+
112+
expect(databaseInfoProvider.determineDatabaseServer).toHaveBeenCalled();
113+
expect(databaseInfoProvider.determineDatabaseModules).toHaveBeenCalled();
114+
});
106115
});
107116

108117
describe('getOrCreateClient', () => {

redisinsight/api/src/modules/database/database-connection.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class DatabaseConnectionService {
4343
lastConnection: new Date(),
4444
timeout: client.options.connectTimeout,
4545
modules: await this.databaseInfoProvider.determineDatabaseModules(client),
46+
version: await this.databaseInfoProvider.determineDatabaseServer(client),
4647
};
4748

4849
// !Temporary. Refresh cluster nodes on connection
@@ -60,7 +61,7 @@ export class DatabaseConnectionService {
6061

6162
await this.repository.update(clientMetadata.databaseId, toUpdate);
6263

63-
const generalInfo = await this.databaseInfoProvider.getRedisGeneralInfo(client)
64+
const generalInfo = await this.databaseInfoProvider.getRedisGeneralInfo(client);
6465

6566
this.recommendationService.check(
6667
clientMetadata,

redisinsight/api/src/modules/database/entities/database.entity.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,8 @@ export class DatabaseEntity {
201201
default: Compressor.NONE,
202202
})
203203
compressor: Compressor;
204+
205+
@Expose()
206+
@Column({ nullable: true })
207+
version: string;
204208
}

redisinsight/api/src/modules/database/models/database.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,14 @@ export class Database {
265265
@IsEnum(Compressor)
266266
@IsOptional()
267267
compressor?: Compressor = Compressor.NONE;
268+
269+
@ApiPropertyOptional({
270+
description: 'The version your Redis server',
271+
type: String,
272+
})
273+
@Expose()
274+
@IsString()
275+
@IsNotEmpty()
276+
@IsOptional()
277+
version?: string;
268278
}

redisinsight/api/src/modules/database/providers/database-info.provider.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,18 @@ describe('DatabaseInfoProvider', () => {
311311
});
312312
});
313313

314+
describe('determineDatabaseServer', () => {
315+
it('get modules by using MODULE LIST command', async () => {
316+
when(mockIORedisClient.call)
317+
.calledWith('info', ['server'])
318+
.mockResolvedValue(mockRedisServerInfoResponse);
319+
320+
const result = await service.determineDatabaseServer(mockIORedisClient);
321+
322+
expect(result).toEqual(mockRedisGeneralInfo.version);
323+
});
324+
});
325+
314326
describe('getRedisGeneralInfo', () => {
315327
beforeEach(() => {
316328
service.getDatabasesCount = jest.fn().mockResolvedValue(16);

redisinsight/api/src/modules/database/providers/database-info.provider.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ export class DatabaseInfoProvider {
8888
}
8989
}
9090

91+
/**
92+
* Determine database server version using "module list" command
93+
* @param client
94+
*/
95+
public async determineDatabaseServer(client: any): Promise<string> {
96+
try {
97+
const reply = convertRedisInfoReplyToObject(await client.call('info', ['server']));
98+
return reply['server']?.redis_version;
99+
} catch (e) {
100+
// continue regardless of error
101+
}
102+
return null;
103+
}
104+
91105
/**
92106
* Determine database modules by using "command info" command for each listed (known/supported) module
93107
* @param client

redisinsight/api/src/modules/database/providers/database.factory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export class DatabaseFactory {
5151
}
5252

5353
model.modules = await this.databaseInfoProvider.determineDatabaseModules(client);
54+
model.version = await this.databaseInfoProvider.determineDatabaseServer(client);
5455
model.lastConnection = new Date();
5556

5657
await client.disconnect();

0 commit comments

Comments
 (0)