Skip to content

Commit e8b2011

Browse files
author
Artem
committed
Merge branch 'main' into feature/RI-4530-fixed_subscription_autodiscovery
# Conflicts: # redisinsight/api/migration/index.ts # redisinsight/api/test/api/database/constants.ts
2 parents 9b531b2 + ffb6820 commit e8b2011

34 files changed

+205
-115
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
import { CloudDatabaseDetails1687166457712 } from './1687166457712-cloud-database-details';
3637

3738
export default [
@@ -69,5 +70,6 @@ export default [
6970
databaseRecommendations1681900503586,
7071
databaseRecommendationParams1683006064293,
7172
Feature1684931530343,
73+
DatabaseRedisServer1686719451753,
7274
CloudDatabaseDetails1687166457712,
7375
];

redisinsight/api/src/__mocks__/databases.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const mockDatabase = Object.assign(new Database(), {
3737
timeout: 30_000,
3838
new: false,
3939
compressor: Compressor.NONE,
40+
version: '7.0',
4041
});
4142

4243
export const mockDatabaseCloudDetails = Object.assign(new CloudDatabaseDetails(), {
@@ -241,6 +242,7 @@ export const mockDatabaseInfoProvider = jest.fn(() => ({
241242
isCluster: jest.fn(),
242243
isSentinel: jest.fn(),
243244
determineDatabaseModules: jest.fn(),
245+
determineDatabaseServer: jest.fn(),
244246
determineSentinelMasterGroups: jest.fn().mockReturnValue([mockSentinelMasterDto]),
245247
determineClusterNodes: jest.fn().mockResolvedValue(mockClusterNodes),
246248
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
@@ -215,4 +215,8 @@ export class DatabaseEntity {
215215
default: Compressor.NONE,
216216
})
217217
compressor: Compressor;
218+
219+
@Expose()
220+
@Column({ nullable: true })
221+
version: string;
218222
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,14 @@ export class Database {
277277
@IsEnum(Compressor)
278278
@IsOptional()
279279
compressor?: Compressor = Compressor.NONE;
280+
281+
@ApiPropertyOptional({
282+
description: 'The version your Redis server',
283+
type: String,
284+
})
285+
@Expose()
286+
@IsString()
287+
@IsNotEmpty()
288+
@IsOptional()
289+
version?: string;
280290
}

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)