From 502a03caa7d6a0b3c63060ef9a563c373dfab618 Mon Sep 17 00:00:00 2001 From: ryjiang Date: Thu, 26 Dec 2024 19:15:55 +0800 Subject: [PATCH] Add backupRBAC and restoreRBAC API (#400) Signed-off-by: ryjiang --- milvus/grpc/User.ts | 56 ++++++++++++++++++++++++++++++++++++++++-- milvus/types/User.ts | 27 ++++++++++++++++---- test/grpc/User.spec.ts | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 7 deletions(-) diff --git a/milvus/grpc/User.ts b/milvus/grpc/User.ts index 53a6085c..03160bbc 100644 --- a/milvus/grpc/User.ts +++ b/milvus/grpc/User.ts @@ -20,12 +20,12 @@ import { listRoleReq, CreatePrivilegeGroupReq, DropPrivilegeGroupReq, - OperatePrivilegeGroupReq, AddPrivilegesToGroupReq, RemovePrivilegesFromGroupReq, - OperatePrivilegeV2Request, GrantPrivilegeV2Request, RevokePrivilegeV2Request, + BackupRBACRequest, + RestoreRBACRequest, OperatePrivilegeGroupType, GrpcTimeOut, ListCredUsersResponse, @@ -35,8 +35,10 @@ import { SelectGrantResponse, HasRoleResponse, ListPrivilegeGroupsResponse, + BackupRBACResponse, promisify, stringToBase64, + RBACMeta, } from '../'; export class User extends Resource { @@ -922,4 +924,54 @@ export class User extends Resource { return promise; } + + /** + * backup RBAC data in Milvus. + * @param {BackupRBACRequest} 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. + * + * @example + * ```javascript + * await milvusClient.BackupRBAC(); + * ``` + * + */ + async backupRBAC(data?: BackupRBACRequest): Promise { + const promise = await promisify( + this.channelPool, + 'BackupRBAC', + data || {}, + data?.timeout || this.timeout + ); + + return promise; + } + + /** + * restore RBAC data in Milvus. + * @param {RestoreRBACRequest} data - The data object. + * @param {RBACMeta} data.RBAC_meta - The rbac meta data returned from the backupRBAC API. + * @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.restoreRBAC({ + * RBAC_meta: rbacMeta, + * }); + * ``` + */ + async restoreRBAC(data: RestoreRBACRequest): Promise { + const promise = await promisify( + this.channelPool, + 'RestoreRBAC', + data, + data.timeout || this.timeout + ); + + return promise; + } } diff --git a/milvus/types/User.ts b/milvus/types/User.ts index 780ab319..811c03f4 100644 --- a/milvus/types/User.ts +++ b/milvus/types/User.ts @@ -4,6 +4,7 @@ import { OperatePrivilegeGroupType, OperatePrivilegeType, } from '../'; +import exp from 'constants'; // base export interface usernameReq extends GrpcTimeOut { @@ -63,6 +64,18 @@ export type RoleResult = { role: RoleEntity; entities: GrantEntity[]; }; +export type PrivelegeGroup = { + group_name: string; // name + privileges: PrivilegeEntity[]; // privileges +}; + +export type RBACMeta = { + users: User[]; + roles: RoleEntity[]; + grants: GrantEntity[]; + privilege_groups: PrivelegeGroup[]; +}; + export interface SelectRoleResponse extends resStatusResponse { results: RoleResult[]; } @@ -115,11 +128,6 @@ 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 } @@ -139,3 +147,12 @@ export interface RemovePrivilegesFromGroupReq extends GrpcTimeOut { group_name: string; // required, group name privileges: PrivilegesTypes[]; // required, privileges } + +export interface BackupRBACRequest extends GrpcTimeOut {} +export interface RestoreRBACRequest extends GrpcTimeOut { + RBAC_meta: RBACMeta; // required, RBAC meta +} + +export interface BackupRBACResponse extends resStatusResponse { + RBAC_meta: RBACMeta; // RBAC meta +} diff --git a/test/grpc/User.spec.ts b/test/grpc/User.spec.ts index 17f187f8..9a27eb02 100644 --- a/test/grpc/User.spec.ts +++ b/test/grpc/User.spec.ts @@ -6,6 +6,7 @@ import { Roles, Privileges, RbacObjects, + RBACMeta, } from '../../milvus'; import { timeoutTest } from '../tools'; import { IP, genCollectionParams, GENERATE_NAME } from '../tools'; @@ -339,10 +340,57 @@ describe(`User Api`, () => { expect(grp.privileges.map(p => p.name)).toContain(Privileges.Search); }); + let backupRBACMeta: RBACMeta; + it(`should backup RBAC meta`, async () => { + const res = await authClient.backupRBAC(); + expect(res.status.error_code).toEqual(ErrorCode.SUCCESS); + // it should have one privilege group + expect(res.RBAC_meta.privilege_groups.length).toEqual(1); + backupRBACMeta = res.RBAC_meta; + }); + it(`drop a privilege group`, async () => { const res = await authClient.dropPrivilegeGroup({ group_name: PRIVILEGE_GRP_NAME, }); expect(res.error_code).toEqual(ErrorCode.SUCCESS); }); + + it(`restore RBAC meta`, async () => { + // make sure no privilege group + const pgrp = await authClient.listPrivilegeGroups(); + // try to find the group + const theGrp = pgrp.privilege_groups.find( + g => g.group_name === PRIVILEGE_GRP_NAME + ); + expect(theGrp).toBeUndefined(); + + // restore meta + const res = await authClient.restoreRBAC({ + RBAC_meta: backupRBACMeta, + }); + expect(res.error_code).toEqual(ErrorCode.SUCCESS); + + // recheck + const listRes = await authClient.listPrivilegeGroups(); + const grp = listRes.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); + + // // restore again should be ok + // const res2 = await authClient.restoreRBAC({ + // RBAC_meta: backupRBACMeta, + // }); + // console.log('res2', res2); + // expect(res2.error_code).toEqual(ErrorCode.SUCCESS); + + // drop it again + const dropRes = await authClient.dropPrivilegeGroup({ + group_name: PRIVILEGE_GRP_NAME, + }); + expect(dropRes.error_code).toEqual(ErrorCode.SUCCESS); + }); });