数据保险柜测试验证
发表于 2026/05/22
0
数据保险柜测试验证
数据保险柜(oGRecorder)是一款数据库日志保护软件。其典型部署场景是运行于virtCCA中,南向对接Dorado Worm存储,北向通过oGRecorderSDK对接数据库,实现对数据库WAL日志的实时同步,形成对用户数据库系统的日志安全保护的软硬一体组合方案。 其中virtCCA基于硬件硬隔离和机密计算能力,为oGRecorder的运行提供隔离于宿主机、REE的安全TEE计算环境;Dorado Worm存储提供Write Once Read Many技术,对数据存储只能新增、禁止删改,实现数据库日志的防篡改保护,防止出现数据库文件、备份数据发生勒索攻击时数据无法恢复;oGRecorder实现类vfs系统支持数据的高效写入和读取,支持和SDK之间安全认证、数据安全写入;而oGRecorderSDK提供完备的文件操作API,供第三方软件调用,进而实现对数据库日志的实时同步、灾备回放。
oGRecorder 7.0.0-RC3版本引入CM-RestAPI组件,支持查询数据保险柜集群信息并执行集群状态控制操作,便于对接外部管控平台,提升集群状态查询与运维控制效率,减少人工操作;通过认证与访问控制机制提升接口调用安全性。
安装部署
oGRecorder安装包生成依赖CBB通用基础模块(https://gitcode.com/opengauss/CBB)
所以需要环境先编译CBB模块。
以openEuler-20.03-LTS arm系统架构为例,优先编译CBB模块
三方库地址:
git clone https://gitcode.com/opengauss/CBB.git -b development
cd CBB/build/linux/opengauss
sh build.sh -3rd [binarylibs path] -m Release -t cmake
CBB模块编译成功后,编译oGRecorder代码生成安装包
git clone https://gitcode.com/opengauss/oGRecorder.git
cd oGRecorder/build
sh build.sh -3rd [binarylibs path] -m Release -t cmake -pkg
执行成功后会在oGRecorder目录下生成安装包;包名:openGauss-oGRecorder-xxxx.tar.gz。
CM-RestAPI是JAVA项目开发 ,所以使用时有软件限制,安装包生成需要如下版本要求:
• Maven版本要求3.9.9
• Java 版本要求 jdk-17
git clone https://gitcode.com/opengauss/CM-RestAPI.git
cd ./CM-RestAPI
sh build.sh
执行成功后会在源码目录下生成对应安装包。
部署参考官方材料:

Rest-API 功能验证
本模块是Java项目,可通过借助三方工具postman、linux工具curl等均可验证体验接口功能;以下介绍curl方式验证。
接口描述参考如下连接描述:
https://docs.opengauss.org/zh/docs/latest/tool_and_commandreference/features.html#支持集群信息查询和推送
api外部访问是需要添加白名单,默认无法外部访问,白名单配置路径:
$GAUSSHOME/bin/restWhiteList 配置如下:
192.168.0.11
192.168.0.12
针对多个Rest-API服务测试我们可以简单通过脚本使用curl工具完成验证:

我们可以使用如上python脚本执行完成接口测试验证。

图2:返回结果json体

图3:返回结果msg中的cms信息

图4:返回结果msg中的oGRecorder信息

图5:返回结果msg中集群的状态信息
该模块涉及到POST类型接口,可以在如上请求方式指定post类型请求
r' -H "Content-type: application/json" -X POST ' \
f'"https://server:8443/CMRestAPI/stopRestApi
oGRecorder SDK API功能验证
该模块是黑匣子核心对外暴露读写数据的API,方便数据库日志信息使用当前模块的API保留到黑匣子中,需要恢复数据时,使用当前模块读取正确的信息,回放数据完成数据恢复。接口涵盖了初始化实例、实例管理、配置管理、错误处理、VFS管理、文件操作等模块。接口定义可以参考官方文档:
https://docs.opengauss.org/zh/docs/latest/tool_and_commandreference/ogrecorder/ogrecorder_api_introduction.html#ogrecorder-sdk-api-文档
该模块采用C语言开发,对外接口测试需要C脚本验证;编写如下C脚本:
1. #include <sys/stat.h>
2. #include <fcntl.h>
3. #include <unistd.h>
4. #include <stdio.h>
5. #include <errno.h>
6. #include <string.h>
7. #include <stdlib.h>
8. #include "gr_api.h"
9.
10. int errorcode = 0;
11. const char *errormsg = NULL;
12.
13. void test_gr_delete_inst(gr_instance_handle ins_handle) {
14. int result = gr_delete_inst(ins_handle);
15. if (result != 0) {
16. gr_get_error(&errorcode, &errormsg);
17. printf("gr_delete_inst interaction failure. code:%d msg:%s\n", errorcode, errormsg);
18. return;
19. }
20. printf("gr_delete_inst interaction success. code:%d\n", result);
21. }
22.
23. void test_gr_vfs_unmount(gr_vfs_handle *vfs) {
24. printf("gr_vfs_unmount in parameter. vfs:%s \n", vfs);
25. int result = gr_vfs_unmount(vfs);
26. if (result != 0) {
27. gr_get_error(&errorcode, &errormsg);
28. printf("gr_vfs_unmount interaction failure. code:%d msg:%s\n", errorcode, errormsg);
29. return;
30. }
31. printf("gr_vfs_unmount interaction success. code:%d\n", result);
32. }
33.
34. void test_gr_file_close(gr_vfs_handle vfs, gr_file_handle *file_handle, bool need_lock) {
35. printf("gr_file_close in parameter. need_lock:%s \n", need_lock ? "true" : "false");
36. int result = gr_file_close(vfs, file_handle, need_lock);
37. if (result != 0) {
38. gr_get_error(&errorcode, &errormsg);
39. printf("gr_file_close interaction failure. code:%d msg:%s\n", errorcode, errormsg);
40. return;
41. }
42. printf("gr_file_close interaction success. code:%d\n", result);
43. }
44.
45. void test_gr_file_pread(gr_vfs_handle vfs, gr_file_handle file_handle, char *buf, long size, int offset) {
46. printf("gr_file_pread in parameter. size:%d offset:%d\n", size, offset);
47. int result = gr_file_pread(vfs, file_handle, buf, size, offset);
48. if (result != size) {
49. gr_get_error(&errorcode, &errormsg);
50. printf("gr_file_pread interaction failure. code:%d msg:%s\n", errorcode, errormsg);
51. return;
52. }
53. printf("gr_file_pread interaction success. code:%d\n", result);
54. }
55.
56. void test_gr_file_pwrite(gr_vfs_handle vfs, gr_file_handle *file_handle, char *buf, long size, int offset) {
57. printf("gr_file_pwrite in parameter. data buf length:%d grite file size:%d offset:%d\n", strlen(buf), size, offset);
58. int result = gr_file_pwrite(vfs, file_handle, buf, size, offset);
59. if (result != size) {
60. gr_get_error(&errorcode, &errormsg);
61. printf("gr_file_pwrite interaction failure. code:%d msg:%s\n", errorcode, errormsg);
62. return;
63. }
64. printf("gr_file_pwrite interaction success. code:%d\n", result);
65. }
66.
67. void test_gr_file_stat(gr_vfs_handle vfs, char *fileName, long long *offset, long long *count, int *mode, char **atime) {
68. int result = gr_file_stat(vfs, fileName, offset, count, mode, atime);
69. if (result != 0) {
70. gr_get_error(&errorcode, &errormsg);
71. printf("gr_file_stat interaction failure. code:%d msg:%s\n", errorcode, errormsg);
72. return;
73. }
74. printf("gr_file_stat interaction success. code:%d\n", result);
75. printf("fileName:%s offset:%ld count:%ld mode:%d atime:%s\n", fileName, *offset, *count, *mode, *atime);
76. }
77.
78. void test_gr_file_open(gr_vfs_handle vfs, const char *fileName, int flags, gr_file_handle *file_handle) {
79. printf("gr_file_open in parameter. fileName:%s\n", fileName);
80. int result = gr_file_open(vfs, fileName, flags, file_handle);
81. if (result != 0) {
82. gr_get_error(&errorcode, &errormsg);
83. printf("gr_file_open interaction failure. code:%d msg:%s\n", errorcode, errormsg);
84. return;
85. }
86. printf("gr_file_open interaction success. code:%d\n", result);
87. }
88.
89. void test_gr_file_create(gr_vfs_handle vfs, const char *fileName, FileParameter *param) {
90. printf("gr_file_create in parameter. fileName:%s\n", fileName);
91. int result = gr_file_create(vfs, fileName, param);
92. if (result != 0) {
93. gr_get_error(&errorcode, &errormsg);
94. printf("gr_file_create interaction failure. code:%d msg:%s\n", errorcode, errormsg);
95. return;
96. }
97. printf("gr_file_create interaction success. code:%d\n", result);
98. }
99.
100. void test_gr_vfs_mount(gr_instance_handle instHandle, char *vfsName, gr_vfs_handle *vfs) {
101. printf("gr_vfs_mount in parameter. vfsName:%s\n", vfsName);
102. int result = gr_vfs_mount(instHandle, vfsName, vfs);
103. if (result != 0) {
104. gr_get_error(&errorcode, &errormsg);
105. printf("gr_vfs_mount interaction failure. code:%d msg:%s\n", errorcode, errormsg);
106. return;
107. }
108. printf("gr_vfs_mount interaction success. code:%d\n", result);
109. }
110.
111. void test_gr_vfs_create(gr_instance_handle instHandle, const char *vfsName, int attrFlag) {
112. printf("gr_vfs_create in parameter. vfsName:%s , attrFlag:%d\n", vfsName, attrFlag);
113. int result = gr_vfs_create(instHandle, vfsName, attrFlag);
114. if (result != 0) {
115. gr_get_error(&errorcode, &errormsg);
116. printf("gr_vfs_create interaction failure. code:%d msg:%s\n", errorcode, errormsg);
117. return;
118. }
119. printf("gr_vfs_create interaction success. code:%d\n", result);
120. }
121.
122. void test_gr_create_inst(char *serverAddr, gr_instance_handle *ins_handle) {
123. int result = gr_create_inst(serverAddr, ins_handle);
124. if (result != 0) {
125. gr_get_error(&errorcode, &errormsg);
126. printf("gr_create_inst interaction failure. code:%d msg:%s\n", errorcode, errormsg);
127. return;
128. }
129. printf("gr_create_inst interaction success. code:%d\n", result);
130. }
131.
132. int main(int argc, char *argv[]) {
133. char *serverAddr = argv[1];
134. // 建连
135. gr_instance_handle ins_handle;
136. test_gr_create_inst(serverAddr, &ins_handle);
137. // 创建目录
138. char *vfsName = "worm_case001";
139. int attrFlag = 0;
140. test_gr_vfs_create(ins_handle, vfsName, attrFlag);
141. // 挂载目录
142. gr_vfs_handle vfs;
143. test_gr_vfs_mount(ins_handle, vfsName, &vfs);
144. // 创建文件
145. char *fileName = "worm_case001_file";
146. FileParameter param;
147. test_gr_file_create(vfs, fileName, ¶m);
148. // 以create模式打开文件
149. gr_file_handle file_handle;
150. int flags = O_RDWR | O_SYNC;
151. test_gr_file_open(vfs, fileName, flags, &file_handle);
152. // 查询文件状态
153. long long foffset, count;
154. int mode;
155. char *atime;
156. test_gr_file_stat(vfs, fileName, &foffset, &count, &mode, &atime);
157. // 文件读写
158. long dataSize = 8 * 1024;
159. char *buf = (char*)malloc(dataSize);
160. memset(buf, 'A', dataSize);
161. int offset = 0;
162. test_gr_file_pwrite(vfs, &file_handle, buf, dataSize, offset);
163. char *read_buf = (char*)malloc(dataSize);
164. test_gr_file_pread(vfs, file_handle, read_buf, dataSize, offset);
165. // 查询文件状态
166. test_gr_file_stat(vfs, fileName, &foffset, &count, &mode, &atime);
167. // 关闭文件指定need_lock为true
168. test_gr_file_close(vfs, &file_handle, true);
169. // 查询文件状态
170. test_gr_file_stat(vfs, fileName, &foffset, &count, &mode, &atime);
171. // 卸载目录
172. test_gr_vfs_unmount(&vfs);
173. // 关闭连接
174. test_gr_delete_inst(ins_handle);
175. return 0;
176. }
关闭文件后指定文件状态为锁定态,首先编译脚本,编译脚本需要oGRecorder编译源码产生的资源,需要指定源码的头文件和动态资源,编译命令如下:
gcc -o Opengauss_gr_Worm_Case001 Opengauss_gr_Worm_Case001.c -I oGRecorder/src/interface -lgrapi -L oGRecorder/output/lib
最后执行脚本指定交互节点的ip

图6:oGRecorder SDK API验证脚本执行结果
文件指定锁定态后,资源不能被篡改、删除,保护资源不被破坏;对资源进行破坏验证:
• 篡改文件内容;通过vim等工具打开资源,添加一些数据,保存文件。

图7:篡改文件验证
• 删除文件;强行删除文件失败。

图8:删除资源验证
参考链接:
• openGauss 文档oGRecorder 概述:
https://docs.opengauss.org/zh/docs/latest/tool_and_commandreference/ogrecorder/ogrecorder_overview.html
• openGauss 文档oGRecorder SDK API 介绍:https://docs.opengauss.org/zh/docs/latest/tool_and_commandreference/ogrecorder/ogrecorder_api_introduction.html
• openGauss 文档oGRecorder 部署与运维指南: https://docs.opengauss.org/zh/docs/latest/tool_and_commandreference/ogrecorder/ogrecorder_deployment_guide.html


