Skip to content

Commit 6df66e0

Browse files
author
Artem
committed
#RI-4132 add workaround for displaying logical database switcher for users without permissions to config command
1 parent ec2b91d commit 6df66e0

File tree

3 files changed

+103
-3
lines changed

3 files changed

+103
-3
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,35 @@ describe('DatabaseInfoProvider', () => {
209209
});
210210
});
211211

212+
describe('getDatabaseCountFromKeyspace', () => {
213+
it('should return 1 since db0 keys presented only', async () => {
214+
const result = await service['getDatabaseCountFromKeyspace']({
215+
db0: 'keys=11,expires=0,avg_ttl=0',
216+
});
217+
218+
expect(result).toBe(1);
219+
});
220+
it('should return 7 since db6 is the last logical databases with known keys', async () => {
221+
const result = await service['getDatabaseCountFromKeyspace']({
222+
db0: 'keys=21,expires=0,avg_ttl=0',
223+
db1: 'keys=31,expires=0,avg_ttl=0',
224+
db6: 'keys=41,expires=0,avg_ttl=0',
225+
});
226+
227+
expect(result).toBe(7);
228+
});
229+
it('should return 1 when empty keySpace provided', async () => {
230+
const result = await service['getDatabaseCountFromKeyspace']({});
231+
232+
expect(result).toBe(1);
233+
});
234+
it('should return 1 when incorrect keySpace provided', async () => {
235+
const result = await service['getDatabaseCountFromKeyspace'](null);
236+
237+
expect(result).toBe(1);
238+
});
239+
});
240+
212241
describe('determineDatabaseModules', () => {
213242
it('get modules by using MODULE LIST command', async () => {
214243
when(mockIORedisClient.call)

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export class DatabaseInfoProvider {
211211
const clientsInfo = info['clients'];
212212
const statsInfo = info['stats'];
213213
const replicationInfo = info['replication'];
214-
const databases = await this.getDatabasesCount(client);
214+
const databases = await this.getDatabasesCount(client, keyspaceInfo);
215215
return {
216216
version: serverInfo?.redis_version,
217217
databases,
@@ -243,10 +243,30 @@ export class DatabaseInfoProvider {
243243
}));
244244
}
245245

246-
public async getDatabasesCount(client: any): Promise<number> {
246+
public async getDatabasesCount(client: any, keyspaceInfo?: object): Promise<number> {
247247
try {
248248
const reply = await client.call('config', ['get', 'databases']);
249249
return reply.length ? parseInt(reply[1], 10) : 1;
250+
} catch (e) {
251+
return this.getDatabaseCountFromKeyspace(keyspaceInfo);
252+
}
253+
}
254+
255+
/**
256+
* Try to determine number of logical database from the `info keyspace`
257+
*
258+
* Note: This is unreliable method which may return less logical databases count that database has
259+
* However this is needed for workaround when `config` command is disabled to understand if we need
260+
* to show logical database switcher on UI
261+
* @param keyspaceInfo
262+
* @private
263+
*/
264+
private getDatabaseCountFromKeyspace(keyspaceInfo: object): number {
265+
try {
266+
const keySpaces = Object.keys(keyspaceInfo);
267+
const matches = keySpaces[keySpaces.length - 1].match(/(\d+)/);
268+
269+
return matches[0] ? parseInt(matches[0], 10) + 1 : 1;
250270
} catch (e) {
251271
return 1;
252272
}

redisinsight/api/test/api/database/GET-databases-id-info.test.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, deps, validateApiCall, before, expect, getMainCheckFn } from '../deps';
1+
import { describe, deps, before, expect, getMainCheckFn, requirements } from '../deps';
22
import { Joi } from '../../helpers/test';
33
const { localDb, request, server, constants, rte } = deps;
44

@@ -61,4 +61,55 @@ describe(`GET /databases/:id/info`, () => {
6161
},
6262
},
6363
].map(mainCheckFn);
64+
65+
66+
67+
describe('ACL', () => {
68+
requirements('rte.acl', 'rte.type=STANDALONE', '!rte.re');
69+
before(async () => rte.data.setAclUserRules('~* +@all'));
70+
beforeEach(rte.data.truncate);
71+
72+
[
73+
{
74+
name: 'Should return 1 for empty databases',
75+
endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID),
76+
before: () => rte.data.setAclUserRules('~* +@all -config'),
77+
responseBody: {
78+
databases: 1,
79+
// ...other fields
80+
},
81+
statusCode: 200,
82+
},
83+
{
84+
name: 'Should return 1 for database with keys created for db0 only',
85+
endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID),
86+
before: async () => {
87+
await rte.data.setAclUserRules('~* +@all -config')
88+
await rte.data.generateStrings();
89+
},
90+
responseBody: {
91+
databases: 1,
92+
// ...other fields
93+
},
94+
statusCode: 200,
95+
},
96+
{
97+
name: 'Should return > 1 databases since data persists there',
98+
endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID),
99+
before: async () => {
100+
await rte.data.setAclUserRules('~* +@all -config')
101+
102+
// generate data in > 0 logical database
103+
await rte.data.executeCommand('select', `${constants.TEST_REDIS_DB_INDEX}`);
104+
await rte.data.executeCommand('set', 'some', 'key');
105+
await rte.data.executeCommand('select', '0');
106+
},
107+
responseBody: {
108+
databases: constants.TEST_REDIS_DB_INDEX + 1,
109+
// ...other fields
110+
},
111+
statusCode: 200,
112+
},
113+
].map(mainCheckFn);
114+
});
64115
});

0 commit comments

Comments
 (0)