diff --git a/milvus/const/milvus.ts b/milvus/const/milvus.ts index f0b73aca..449c553b 100644 --- a/milvus/const/milvus.ts +++ b/milvus/const/milvus.ts @@ -443,3 +443,8 @@ export enum RANKER_TYPE { RRF = 'rrf', WEIGHTED = 'weighted', } + +export enum OperatePrivilegeGroupType { + AddPrivilegesToGroup = 0, + RemovePrivilegesFromGroup = 1, +} diff --git a/milvus/grpc/User.ts b/milvus/grpc/User.ts index 9a4abaf7..1aef7cc3 100644 --- a/milvus/grpc/User.ts +++ b/milvus/grpc/User.ts @@ -18,6 +18,12 @@ import { ListGrantsReq, HasRoleReq, listRoleReq, + CreatePrivilegeGroupReq, + DropPrivilegeGroupReq, + OperatePrivilegeGroupReq, + AddPrivilegesToGroupReq, + RemovePrivilegesFromGroupReq, + OperatePrivilegeGroupType, GrpcTimeOut, ListCredUsersResponse, ResStatus, @@ -25,6 +31,7 @@ import { SelectUserResponse, SelectGrantResponse, HasRoleResponse, + ListPrivilegeGroupsResponse, promisify, stringToBase64, } from '../'; @@ -680,4 +687,195 @@ export class User extends Resource { hasRole: result.results.map(r => r.role.name).includes(data.roleName), }; } + + /** + * Create a new privilege group in Milvus. + * @param {CreatePrivilegeGroupReq} data - The privilege group data. + * @param {string} data.group_name - The name of the new privilege group. + * @param {number} [data.timeout] - An optional duration of time in milliseconds to allow for the RPC. If it is set to undefined, the client keeps waiting until the server responds or error occurs. Default is undefined. + * + * @returns {Promise} The response status. + * + * @example + * ```javascript + * milvusClient.createPrivilegeGroup({ + * group_name: 'exampleGroup', + * }); + * ``` + */ + async createPrivilegeGroup( + data: CreatePrivilegeGroupReq + ): Promise { + const promise = await promisify( + this.channelPool, + 'CreatePrivilegeGroup', + data, + data.timeout || this.timeout + ); + + return promise; + } + + /** + * Drop a privilege group in Milvus. + * @param {DropPrivilegeGroupReq} data - The privilege group data. + * @param {string} data.group_name - The name of the privilege group to be dropped. + * @param {number} [data.timeout] - An optional duration of time in milliseconds to allow for the RPC. If it is set to undefined, the client keeps waiting until the server responds or error occurs. Default is undefined. + * + * @returns {Promise} The response status. + * + * @example + * ```javascript + * await milvusClient.dropPrivilegeGroup({ + * group_name: 'exampleGroup', + * }); + * ``` + */ + async dropPrivilegeGroup(data: DropPrivilegeGroupReq): Promise { + const promise = await promisify( + this.channelPool, + 'DropPrivilegeGroup', + data, + data.timeout || this.timeout + ); + + return promise; + } + + /** + * List all privilege groups in Milvus. + * @param {GrpcTimeOut} data - The data object. + * @param {number} [data.timeout] - An optional duration of time in milliseconds to allow for the RPC. If it is set to undefined, the client keeps waiting until the server responds or error occurs. Default is undefined. + * + * @returns {Promise} The response object. + * @returns {ResStatus} response.status - The response status. + * @returns {number} response.status.error_code - The error code number. + * @returns {string} response.status.reason - The cause of the error, if any. + * @returns {PrivelegeGroup[]} response.privilege_groups - An array of privilege groups. + * @returns {string} response.privilege_groups.group_name - The name of the privilege group. + * @returns {PrivilegeEntity[]} response.privilege_groups.privileges - An array of privileges. + * @returns {string} response.privilege_groups.privileges.name - The name of the privilege. + * + * @example + * ```javascript + * await milvusClient.listPrivilegeGroups(); + * ``` + */ + async listPrivilegeGroups( + data?: GrpcTimeOut + ): Promise { + const promise = await promisify( + this.channelPool, + 'ListPrivilegeGroups', + {}, + data?.timeout || this.timeout + ); + + return promise; + } + + /** + * Operate a privilege group in Milvus. + * @param {OperatePrivilegeGroupReq} data - The privilege group data. + * @param {string} data.group_name - The name of the privilege group to be operated. + * @param {PrivilegeEntity[]} data.privileges - The privileges to be operated. + * @param {OperatePrivilegeGroupType} data.type - The operation type. + * @param {number} [data.timeout] - An optional duration of time in milliseconds to allow for the RPC. If it is set to undefined, the client keeps waiting until the server responds or error occurs. Default is undefined. + * @returns {Promise} The response object. + * + * @example + * ```javascript + * await milvusClient.operatePrivilegeGroup({ + * group_name: 'exampleGroup', + * privileges: [{name: 'CreateCollection'}], + * type: OperatePrivilegeGroupType.AddPrivilegesToGroup, + * }); + * ``` + */ + async operatePrivilegeGroup( + data: OperatePrivilegeGroupReq + ): Promise { + const promise = await promisify( + this.channelPool, + 'OperatePrivilegeGroup', + data, + data.timeout || this.timeout + ); + + return promise; + } + + /** + * add privileges to a privilege group in Milvus. + * @param {AddPrivilegesToGroupReq} data - The privilege group data. + * @param {string} data.group_name - The name of the privilege group to be operated. + * @param {string[]} data.privileges - The privileges to be added to the group. + * + * @returns {Promise} The response object. + * @returns {ResStatus} response.status - The response status. + * @returns {number} response.status.error_code - The error code number. + * @returns {string} response.status.reason - The cause of the error, if any. + * + * @example + * ```javascript + * await milvusClient.addPrivilegesToGroup({ + * group_name: 'exampleGroup', + * privileges: ['CreateCollection', 'DropCollection'], + * }); + * + * ``` + */ + async addPrivilegesToGroup( + data: AddPrivilegesToGroupReq + ): Promise { + const promise = await promisify( + this.channelPool, + 'OperatePrivilegeGroup', + { + group_name: data.group_name, + privileges: data.privileges.map(p => ({ name: p })), + type: OperatePrivilegeGroupType.AddPrivilegesToGroup, + }, + data.timeout || this.timeout + ); + + return promise; + } + + /** + * remove privileges from a privilege group in Milvus. + * @param {RemovePrivilegesFromGroupReq} data - The privilege group data. + * @param {string} data.group_name - The name of the privilege group to be operated. + * @param {string[]} data.privileges - The privileges to be removed from the group. + * + * @returns {Promise} The response object. + * @returns {ResStatus} response.status - The response status. + * @returns {number} response.status.error_code - The error code number. + * @returns {string} response.status.reason - The cause of the error, if any. + * + * @example + * ```javascript + * await milvusClient.removePrivilegesFromGroup({ + * group_name: 'exampleGroup', + * privileges: ['CreateCollection', 'DropCollection'], + * }); + * + * ``` + */ + async removePrivilegesFromGroup( + data: RemovePrivilegesFromGroupReq + ): Promise { + const promise = await promisify( + this.channelPool, + 'OperatePrivilegeGroup', + { + group_name: data.group_name, + privileges: data.privileges.map(p => ({ name: p })), + type: OperatePrivilegeGroupType.RemovePrivilegesFromGroup, + }, + data.timeout || this.timeout + ); + + return promise; + } } diff --git a/milvus/types/Common.ts b/milvus/types/Common.ts index 5d3f0615..b15f996b 100644 --- a/milvus/types/Common.ts +++ b/milvus/types/Common.ts @@ -36,7 +36,8 @@ export interface GrpcTimeOut { export type PrivilegesTypes = | CollectionPrivileges | UserPrivileges - | GlobalPrivileges; + | GlobalPrivileges + | string; export interface ResStatus { error_code: string | number; diff --git a/milvus/types/User.ts b/milvus/types/User.ts index fba62b3a..8ded43e6 100644 --- a/milvus/types/User.ts +++ b/milvus/types/User.ts @@ -1,5 +1,5 @@ import { GrpcTimeOut, PrivilegesTypes, resStatusResponse } from './Common'; -import { RbacObjects } from '../'; +import { RbacObjects, OperatePrivilegeGroupType } from '../'; // base export interface usernameReq extends GrpcTimeOut { @@ -84,3 +84,36 @@ export interface SelectGrantResponse extends resStatusResponse { export interface HasRoleResponse extends resStatusResponse { hasRole: boolean; } + +export interface CreatePrivilegeGroupReq extends GrpcTimeOut { + group_name: string; // required, name +} + +export interface DropPrivilegeGroupReq extends GrpcTimeOut { + group_name: string; // required, name +} + +export type PrivelegeGroup = { + group_name: string; // name + privileges: PrivilegeEntity[]; // privileges +}; + +export interface ListPrivilegeGroupsResponse extends resStatusResponse { + privilege_groups: PrivelegeGroup[]; // privilege groups +} + +export interface OperatePrivilegeGroupReq extends GrpcTimeOut { + group_name: string; // required, group name + privileges: PrivilegeEntity[]; // required, privileges + type: OperatePrivilegeGroupType; // required, operation type +} + +export interface AddPrivilegesToGroupReq extends GrpcTimeOut { + group_name: string; // required, group name + privileges: PrivilegesTypes[]; // required, privileges +} + +export interface RemovePrivilegesFromGroupReq extends GrpcTimeOut { + group_name: string; // required, group name + privileges: PrivilegesTypes[]; // required, privileges +} diff --git a/test/grpc/User.spec.ts b/test/grpc/User.spec.ts index 52f30f7b..46d5677b 100644 --- a/test/grpc/User.spec.ts +++ b/test/grpc/User.spec.ts @@ -1,3 +1,4 @@ +import exp from 'constants'; import { MilvusClient, ERROR_REASONS, @@ -6,17 +7,19 @@ import { Roles, Privileges, RbacObjects, + OperatePrivilegeGroupType, } from '../../milvus'; import { timeoutTest } from '../tools'; import { IP, genCollectionParams, GENERATE_NAME } from '../tools'; -const milvusClient = new MilvusClient({ address: IP }); +const milvusClient = new MilvusClient({ address: IP, logLevel: 'info' }); let authClient: MilvusClient; const USERNAME = 'username'; const PASSWORD = '123456'; const NEW_PASSWORD = '1234567'; const ROLE_NAME = GENERATE_NAME('role'); const COLLECTION_NAME = GENERATE_NAME(); +const PRIVILEGE_GRP_NAME = GENERATE_NAME('privilege'); describe(`User Api`, () => { beforeAll(async () => { @@ -274,9 +277,57 @@ describe(`User Api`, () => { } }); - // last test + // last test for user it(`Auth client delete user expect success`, async () => { const res = await authClient.deleteUser({ username: USERNAME }); expect(res.error_code).toEqual(ErrorCode.SUCCESS); }); + + it(`create a privilege group`, async () => { + const res = await authClient.createPrivilegeGroup({ + group_name: PRIVILEGE_GRP_NAME, + }); + expect(res.error_code).toEqual(ErrorCode.SUCCESS); + }); + + it(`add privileges to a privilege group`, async () => { + const res = await authClient.addPrivilegesToGroup({ + group_name: PRIVILEGE_GRP_NAME, + privileges: [Privileges.Query], + }); + + expect(res.error_code).toEqual(ErrorCode.SUCCESS); + + const res2 = await authClient.operatePrivilegeGroup({ + group_name: PRIVILEGE_GRP_NAME, + privileges: [{ name: Privileges.Search }], + type: OperatePrivilegeGroupType.AddPrivilegesToGroup, + }); + expect(res2.error_code).toEqual(ErrorCode.SUCCESS); + }); + + it(`remove privileges from a privilege group`, async () => { + const res = await authClient.removePrivilegesFromGroup({ + group_name: PRIVILEGE_GRP_NAME, + privileges: [Privileges.Query], + }); + expect(res.error_code).toEqual(ErrorCode.SUCCESS); + }); + + it(`list privilege groups`, async () => { + const res = await authClient.listPrivilegeGroups(); + expect(res.privilege_groups.length).toBeGreaterThan(0); + const grp = res.privilege_groups.find( + g => g.group_name === PRIVILEGE_GRP_NAME + )!; + expect(grp.group_name).toEqual(PRIVILEGE_GRP_NAME); + expect(grp.privileges.map(p => p.name)).toContain(Privileges.Search); + }); + + it(`drop a privilege group`, async () => { + const res = await authClient.dropPrivilegeGroup({ + group_name: PRIVILEGE_GRP_NAME, + }); + expect(res.error_code).toEqual(ErrorCode.SUCCESS); + }); });