Skip to content

Commit fae5e99

Browse files
committed
Merge branch 'main' into ri-explain-plugin
2 parents 5d54e87 + 913bcf4 commit fae5e99

File tree

239 files changed

+7429
-2119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

239 files changed

+7429
-2119
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ aliases:
8888
- mods-preview # OSS Standalone and all preview modules
8989
- oss-st-6-tls # OSS Standalone v6 with TLS enabled
9090
- oss-st-6-tls-auth # OSS Standalone v6 with TLS auth required
91+
- oss-st-6-tls-auth-ssh # OSS Standalone v6 with TLS auth required through ssh
9192
- oss-clu # OSS Cluster
9293
- oss-clu-tls # OSS Cluster with TLS enabled
9394
- oss-sent # OSS Sentinel

redisinsight/api/config/default.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default {
5555
staticContent: !!process.env.SERVER_STATIC_CONTENT || false,
5656
buildType: process.env.BUILD_TYPE || 'ELECTRON',
5757
appVersion: process.env.APP_VERSION || '2.0.0',
58-
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 10000,
58+
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 25000,
5959
excludeRoutes: [],
6060
excludeAuthRoutes: [],
6161
},
@@ -108,14 +108,14 @@ export default {
108108
},
109109
guides: {
110110
updateUrl: process.env.GUIDES_UPDATE_URL
111-
|| 'https://github.com/RedisInsight/Guides/releases/download/latest',
111+
|| 'https://github.com/RedisInsight/Guides/releases/download/release',
112112
zip: process.env.GUIDES_ZIP || dataZipFileName,
113113
buildInfo: process.env.GUIDES_CHECKSUM || buildInfoFileName,
114114
devMode: !!process.env.GUIDES_DEV_PATH,
115115
},
116116
tutorials: {
117117
updateUrl: process.env.TUTORIALS_UPDATE_URL
118-
|| 'https://github.com/RedisInsight/Tutorials/releases/download/latest',
118+
|| 'https://github.com/RedisInsight/Tutorials/releases/download/release',
119119
zip: process.env.TUTORIALS_ZIP || dataZipFileName,
120120
buildInfo: process.env.TUTORIALS_CHECKSUM || buildInfoFileName,
121121
devMode: !!process.env.TUTORIALS_DEV_PATH,

redisinsight/api/config/ormconfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { SettingsEntity } from 'src/modules/settings/entities/settings.entity';
1010
import { CaCertificateEntity } from 'src/modules/certificate/entities/ca-certificate.entity';
1111
import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity';
1212
import { DatabaseEntity } from 'src/modules/database/entities/database.entity';
13+
import { SshOptionsEntity } from 'src/modules/ssh/entities/ssh-options.entity';
1314
import migrations from '../migration';
1415
import * as config from '../src/utils/config';
1516

@@ -31,6 +32,7 @@ const ormConfig = {
3132
PluginStateEntity,
3233
NotificationEntity,
3334
DatabaseAnalysisEntity,
35+
SshOptionsEntity,
3436
],
3537
migrations,
3638
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class sshOptions1673035852335 implements MigrationInterface {
4+
name = 'sshOptions1673035852335'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`CREATE TABLE "ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"))`);
8+
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, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
9+
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") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new" FROM "database_instance"`);
10+
await queryRunner.query(`DROP TABLE "database_instance"`);
11+
await queryRunner.query(`ALTER TABLE "temporary_database_instance" RENAME TO "database_instance"`);
12+
await queryRunner.query(`CREATE TABLE "temporary_ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"), CONSTRAINT "FK_fe3c3f8b1246e4824a3fb83047d" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
13+
await queryRunner.query(`INSERT INTO "temporary_ssh_options"("id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId") SELECT "id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId" FROM "ssh_options"`);
14+
await queryRunner.query(`DROP TABLE "ssh_options"`);
15+
await queryRunner.query(`ALTER TABLE "temporary_ssh_options" RENAME TO "ssh_options"`);
16+
}
17+
18+
public async down(queryRunner: QueryRunner): Promise<void> {
19+
await queryRunner.query(`ALTER TABLE "ssh_options" RENAME TO "temporary_ssh_options"`);
20+
await queryRunner.query(`CREATE TABLE "ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"))`);
21+
await queryRunner.query(`INSERT INTO "ssh_options"("id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId") SELECT "id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId" FROM "temporary_ssh_options"`);
22+
await queryRunner.query(`DROP TABLE "temporary_ssh_options"`);
23+
await queryRunner.query(`ALTER TABLE "database_instance" RENAME TO "temporary_database_instance"`);
24+
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, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
25+
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") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new" FROM "temporary_database_instance"`);
26+
await queryRunner.query(`DROP TABLE "temporary_database_instance"`);
27+
await queryRunner.query(`DROP TABLE "ssh_options"`);
28+
}
29+
30+
}

redisinsight/api/migration/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { databaseAnalysisExpirationGroups1664886479051 } from './1664886479051-d
2222
import { workbenchExecutionTime1667368983699 } from './1667368983699-workbench-execution-time';
2323
import { database1667477693934 } from './1667477693934-database';
2424
import { databaseNew1670252337342 } from './1670252337342-database-new';
25+
import { sshOptions1673035852335 } from './1673035852335-ssh-options';
2526

2627
export default [
2728
initialMigration1614164490968,
@@ -48,4 +49,5 @@ export default [
4849
workbenchExecutionTime1667368983699,
4950
database1667477693934,
5051
databaseNew1670252337342,
52+
sshOptions1673035852335,
5153
];

redisinsight/api/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"start:prod": "cross-env NODE_ENV=production node dist/src/main",
2828
"test": "cross-env NODE_ENV=test ./node_modules/.bin/jest -w 1",
2929
"test:watch": "cross-env NODE_ENV=test jest --watch -w 1",
30-
"test:cov": "cross-env NODE_ENV=test ./node_modules/.bin/jest --coverage -w 1",
30+
"test:cov": "cross-env NODE_ENV=test ./node_modules/.bin/jest --forceExit --coverage -w 1",
3131
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand -w 1",
3232
"test:e2e": "jest --config ./test/jest-e2e.json -w 1",
3333
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -d ./config/ormconfig.ts",
@@ -53,6 +53,7 @@
5353
"body-parser": "^1.19.0",
5454
"class-transformer": "^0.2.3",
5555
"class-validator": "^0.12.2",
56+
"detect-port": "^1.5.1",
5657
"dotenv": "^16.0.0",
5758
"express": "^4.17.1",
5859
"fs-extra": "^10.0.0",
@@ -67,6 +68,7 @@
6768
"socket.io": "^4.4.0",
6869
"source-map-support": "^0.5.19",
6970
"sqlite3": "^5.0.11",
71+
"ssh2": "^1.11.0",
7072
"swagger-ui-express": "^4.1.4",
7173
"typeorm": "^0.3.9",
7274
"uuid": "^8.3.2",
@@ -84,6 +86,7 @@
8486
"@types/lodash": "^4.14.167",
8587
"@types/node": "14.14.10",
8688
"@types/socket.io": "^3.0.2",
89+
"@types/ssh2": "^1.11.6",
8790
"@types/supertest": "^2.0.8",
8891
"@typescript-eslint/eslint-plugin": "^4.8.1",
8992
"@typescript-eslint/parser": "^4.8.1",

redisinsight/api/src/__mocks__/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const mockRepository = jest.fn(() => ({
5454
findOneBy: jest.fn(),
5555
find: jest.fn(),
5656
findByIds: jest.fn(),
57+
merge: jest.fn(),
5758
create: jest.fn(),
5859
save: jest.fn(),
5960
insert: jest.fn(),

redisinsight/api/src/__mocks__/databases.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import { pick } from 'lodash';
99
import { RedisDatabaseInfoResponse } from 'src/modules/database/dto/redis-info.dto';
1010
import { DatabaseOverview } from 'src/modules/database/models/database-overview';
1111
import { ClientContext, ClientMetadata } from 'src/common/models';
12+
import {
13+
mockSshOptionsBasic,
14+
mockSshOptionsBasicEntity,
15+
mockSshOptionsPrivateKey,
16+
mockSshOptionsPrivateKeyEntity,
17+
} from 'src/__mocks__/ssh';
1218

1319
export const mockDatabaseId = 'a77b23c1-7816-4ea4-b61f-d37795a0f805-db-id';
1420

@@ -34,6 +40,29 @@ export const mockDatabaseEntity = Object.assign(new DatabaseEntity(), {
3440
encryption: null,
3541
});
3642

43+
export const mockDatabaseWithSshBasic = Object.assign(new Database(), {
44+
...mockDatabase,
45+
ssh: true,
46+
sshOptions: mockSshOptionsBasic,
47+
});
48+
49+
export const mockDatabaseWithSshBasicEntity = Object.assign(new DatabaseEntity(), {
50+
...mockDatabaseWithSshBasic,
51+
encryption: null,
52+
sshOptions: mockSshOptionsBasicEntity,
53+
});
54+
55+
export const mockDatabaseWithSshPrivateKey = Object.assign(new Database(), {
56+
...mockDatabase,
57+
ssh: true,
58+
sshOptions: mockSshOptionsPrivateKey,
59+
});
60+
61+
export const mockDatabaseWithSshPrivateKeyEntity = Object.assign(new DatabaseEntity(), {
62+
...mockDatabaseWithSshPrivateKey,
63+
sshOptions: mockSshOptionsPrivateKeyEntity,
64+
});
65+
3766
export const mockDatabaseWithAuth = Object.assign(new Database(), {
3867
...mockDatabase,
3968
username: 'some username',
@@ -181,6 +210,7 @@ export const mockDatabaseService = jest.fn(() => ({
181210

182211
export const mockDatabaseConnectionService = jest.fn(() => ({
183212
getOrCreateClient: jest.fn().mockResolvedValue(mockIORedisClient),
213+
createClient: jest.fn().mockResolvedValue(mockIORedisClient),
184214
}));
185215

186216
export const mockDatabaseInfoProvider = jest.fn(() => ({

redisinsight/api/src/__mocks__/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ export * from './server';
1717
export * from './redis-enterprise';
1818
export * from './redis-sentinel';
1919
export * from './database-import';
20+
export * from './redis-client';
21+
export * from './ssh';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { IRedisClientInstance, RedisService } from 'src/modules/redis/redis.service';
2+
import { mockCommonClientMetadata } from 'src/__mocks__/common';
3+
import { mockIORedisClient } from 'src/__mocks__/redis';
4+
import { ClientMetadata } from 'src/common/models';
5+
6+
export const mockRedisClientInstance: IRedisClientInstance = {
7+
id: RedisService.generateId(mockCommonClientMetadata),
8+
clientMetadata: mockCommonClientMetadata,
9+
client: mockIORedisClient,
10+
lastTimeUsed: 1619791508019,
11+
};
12+
13+
export const generateMockRedisClientInstance = (clientMetadata: Partial<ClientMetadata>): IRedisClientInstance => ({
14+
id: RedisService.generateId(clientMetadata as ClientMetadata),
15+
clientMetadata: clientMetadata as ClientMetadata,
16+
client: mockIORedisClient,
17+
lastTimeUsed: Date.now(),
18+
});

0 commit comments

Comments
 (0)