Wazuh DBSync 事务操作冒烟测试实战指南:基于 dbsync_test_tool 的 Txn Operation 全流程解析 📅 发布时间:2026/9/14 21:13:58 👁 浏览次数: Wazuh DBSync 事务操作冒烟测试实战指南基于 dbsync_test_tool 的 Txn Operation 全流程解析【免费下载链接】wazuhWazuh - The Open Source Security Platform. Unified XDR and SIEM protection for endpoints and cloud workloads.项目地址: https://gitcode.com/GitHub_Trending/wa/wazuh本文以 Wazuh 开源仓库中 DBSync 模块的txnOperation冒烟测试为切入点系统讲解如何在 SQLite 数据库上通过dbsync_test_tool完成建库 → 开启事务 → 批量插入 → 读取删除行 → 事务内修改 → 提交关闭的完整事务链路。读完本文你将掌握 DBSync 事务型 API 的 JSON 动作格式、命令行执行方式、输出产物含义以及事务同步在 Wazuh 数据同步管道中的底层实现原理。一、什么是 Txn Operation 冒烟测试在 Wazuh 中DBSync 是一个负责把内存中的结构化数据如进程、文件信息与本地 SQLite 数据库保持同步的 C 共享库其完整接口定义位于 include/dbsync.h。为了验证整条 DBSync 库 API 在真实运行环境中可用仓库维护了一套基于dbsync_test_tool的冒烟测试Smoke Tests总入口说明见 smokeTests/Readme.md每个子目录对应一个独立用例包含验证该用例所需的全部 JSON 文件与专属说明文档。txnOperation就是其中一个专门覆盖事务Transaction语义的用例对应文档为 smokeTests/txnOperation/Readme.md。它把 DBSync 的事务型 API 完整串联起来开启事务后先插入一批进程快照行再查询已被外部删除的行删除行 diff随后在事务内修改既有记录最后关闭事务提交全部变更——整个过程模拟了 Wazuh 的 FIM/进程监控场景中多行数据批处理 差异计算的典型需求。事务用例目录包含 6 个文件文件作用Readme.md用例说明与执行命令createTxn.json开启事务动作inputSyncRowInsertTxn.json事务内插入行动作pksGetDeletedRows.json以主键形式返回删除行fullyGetDeletedRows.json以完整字段形式返回删除行inputSyncRowModifiedTxn.json事务内修改行动作closeTxn.json关闭事务动作二、事务操作的核心流程原文档将整个用例抽象为 6 个步骤这也是 DBSync 事务型数据同步的标准生命周期创建数据库基于 smokeTests/config.json 中sql_statement选项建表。创建事务通过createTxn.json指定参与事务的表。插入数据把inputSyncRowInsertTxn.json中的数据写入数据库事务内。获取删除行用pksGetDeletedRows.json/fullyGetDeletedRows.json定义返回信息的细节仅主键 vs 全部字段。更新数据库用inputSyncRowModifiedTxn.json的数据修改既有记录。关闭事务提交事务并释放事务上下文。这 6 步与 DBSync 事务型 API 一一对应dbsync_create_txn、dbsync_sync_txn_row、dbsync_get_deleted_rows、dbsync_close_txn。其中步骤 3 和 5 使用的是事务专用的行同步接口dbsync_sync_txn_row区别于普通接口dbsync_sync_row步骤 4 的删除行查询则是事务独有的差异提取能力——普通同步路径并不提供。三、环境准备编译并获取 dbsync_test_tool冒烟测试的执行依赖dbsync_test_tool二进制。它位于 testtool是一个把 DBSync 库当作黑盒驱动的命令行测试工具用户传入若干 JSON 动作文件工具逐个应用到数据库并输出结果文件详见 testtool/Readme.md。编译整个 Wazuh 工程release 或 debug 模式均可即可获得该工具make TARGETserver|agent DEBUG1编译产物中即包含dbsync_test_tool可执行文件。从 testtool/main.cpp 的入口逻辑可以看出工具的工作方式解析命令行参数-c配置文件、-a动作列表、-o输出目录参数解析实现见 testtool/cmdArgsHelper.h读取 config JSON 中的db_name、db_type、host_type、persistance、sql_statement五个字段调用dbsync_initialize注册日志回调并根据persistance是否等于1选择dbsync_create_persistent持久化或dbsync_create临时创建句柄按顺序读取-a中每个动作文件依据其中的action字段通过工厂创建对应动作对象并执行全部完成后调用dbsync_teardown清理。工具的架构关系可参考官方提供的架构图四、配置数据库config.json 逐字段解读事务用例本身不携带 config而是共用冒烟测试目录下的 smokeTests/config.json{ db_name: temp.db, db_type: 1, host_type: 1, persistance: , sql_statement: CREATE TABLE processes(pid BIGINT, name TEXT, path TEXT, cmdline TEXT, state TEXT, cwd TEXT, root TEXT, uid BIGINT, gid BIGINT, euid BIGINT, egid BIGINT, suid BIGINT, sgid BIGINT, on_disk INTEGER, wired_size BIGINT, resident_size BIGINT, total_size BIGINT, user_time BIGINT, system_time BIGINT, disk_bytes_read BIGINT, disk_bytes_written BIGINT, start_time BIGINT, parent BIGINT, pgroup BIGINT, threads INTEGER, nice INTEGER, is_elevated_token INTEGER, elapsed_time BIGINT, handle_count BIGINT, percent_processor_time BIGINT, upid BIGINT HIDDEN, uppid BIGINT HIDDEN, cpu_type INTEGER HIDDEN, cpu_subtype INTEGER HIDDEN, phys_footprint BIGINT HIDDEN, PRIMARY KEY (pid)) WITHOUT ROWID;CREATE TABLE processes_sockets(socket_id BIGINT, pid BIGINT, PRIMARY KEY (socket_id)) WITHOUT ROWID; }各字段含义如下字段语义与 testtool/Readme.md 及 testtool/main.cpp 中的解析逻辑一致db_name数据库文件名本用例为temp.dbdb_type数据库引擎类型1对应DbEngineType::SQLITE3当前唯一支持的类型其他值会映射为DbEngineType::UNDEFINEDhost_type宿主类型0对应HostType::MANAGERManager 端1对应HostType::AGENTAgent 端persistance持久化开关空串表示使用临时库走dbsync_create1表示持久化走dbsync_create_persistent即 dbsync.h 中DbManagement::PERSISTENT语义sql_statement建表 SQL。本用例一次创建两张表processes进程信息表字段覆盖 pid、name、path、cmdline、state 等 35 个列含upid、uppid、cpu_type等HIDDEN列主键为pidWITHOUT ROWIDprocesses_sockets进程与套接字关联表主键socket_id。注意sql_statement中两张表之间没有分号分隔符直接以;CREATE TABLE拼接为一条完整语句传给 DBSync——这正是 DBSync 支持多表一次性初始化结构的用法。五、动作文件逐一解析事务用例的所有动作文件都遵循统一的 JSON 格式顶层action字段指定操作名body字段携带操作参数。动作名到实现类的映射定义在 testtool/factoryAction.h。5.1 创建事务createTxn.json{ action: dbsync_create_txn, body: { tables: [processes] } }dbsync_create_txn在 testtool/action.h 中由CreateTransactionAction实现底层调用ctx-txnContext dbsync_create_txn(ctx-handle, jsonTables.get(), 0, 100, callbackData);其中0为工作线程数0 表示由硬件并发度决定100为事务行数上限maxRows回调使用txnCallback——该回调会把每次返回的数据追加写入output/txn_事务句柄.json文件。动作执行成功后会在输出目录生成action_1.json内容形如{txn_context: true}表示事务上下文创建成功。dbsync_create_txn的完整签名与语义参见 include/dbsync.h。5.2 事务内插入inputSyncRowInsertTxn.json{ action: dbsync_sync_txn_row, body: { table: processes, data: [ { pid: 4, name: System, path: , cmdline: , state: , cwd: , root: , uid: -1, gid: -1, euid: -1, egid: -1, suid: -1, sgid: -1, on_disk: -1, wired_size: -1, resident_size: -1, total_size: -1, user_time: -1, system_time: -1, disk_bytes_read: -1, disk_bytes_written: -1, start_time: -1, parent: 0, pgroup: -1, threads: 164, nice: -1, is_elevated_token: false, elapsed_time: -1, handle_count: -1, percent_processor_time: -1 }, { pid: 5, name: System, path: /usr/lib, cmdline: whoami, state: , cwd: , root: , uid: -1, gid: -1, euid: -1, egid: -1, suid: -1, sgid: -1, on_disk: -1, wired_size: -1, resident_size: -1, total_size: -1, user_time: -1, system_time: -1, disk_bytes_read: -1, disk_bytes_written: -1, start_time: -1, parent: 0, pgroup: -1, threads: 164, nice: -1, is_elevated_token: false, elapsed_time: -1, handle_count: -1, percent_processor_time: -1 } ] } }dbsync_sync_txn_row由SyncTxnRowsAction实现核心调用为dbsync_sync_txn_row(ctx-txnContext, jsInput.get())——注意它接收的是事务句柄而非全局句柄。两条进程记录pid4、pid5均以-1/false占位未知数值字段模拟系统进程快照中大量未采集字段的场景。5.3 获取删除行pksGetDeletedRows.json 与 fullyGetDeletedRows.json两个文件内容完全相同{ action: dbsync_get_deleted_rows }它们都触发GetDeletedRowsAction底层调用dbsync_get_deleted_rows(ctx-txnContext, callbackData)。删除行数据通过回调写入独立的callback.action_id.json文件。两者差异在于信息细节由谁定义从 tests/interface/dbsync_test.cpp 中的GetDeletedRowsOnlyPKs与GetDeletedRowsAllAttributes两个测试用例可以看出pks仅主键与fully全部属性两种模式是 DBSync 事务查询的两种返回形态——前者只回传主键字段如{pid:4}用于快速比对后者回传该行的完整字段集合用于完整还原删除记录。在同一事务中依次执行pksGetDeletedRows与fullyGetDeletedRows即可分别拿到两种粒度的删除 diff。在本用例脚本中两者先后出现正是为了验证同一事务下两种查询模式的正确性。5.4 事务内修改inputSyncRowModifiedTxn.json{ action: dbsync_sync_txn_row, body: { table: processes, data: [ { pid: 4, name: User, path: , cmdline: Guake, state: , cwd: , root: , uid: -1, gid: -1, euid: -1, egid: -1, suid: -1, sgid: -1, on_disk: -1, wired_size: -1, resident_size: -1, total_size: -1, user_time: -1, system_time: -1, disk_bytes_read: -1, disk_bytes_written: -1, start_time: -1, parent: 1, pgroup: -1, threads: 164, nice: -1, is_elevated_token: false, elapsed_time: -1, handle_count: -1, percent_processor_time: -1 } ] } }同样是dbsync_sync_txn_row动作但 pid4 的记录的name从System变为User、cmdline从空变为Guake、parent从 0 变为 1。因为主键pid未变DBSync 会将其识别为**更新UPDATE**而非新增——这验证了dbsync_sync_txn_row的插入或更新upsert语义。5.5 关闭事务closeTxn.json{ action: dbsync_close_txn }dbsync_close_txn由CloseTransactionAction实现调用dbsync_close_txn(ctx-txnContext)返回{txn_context: 返回码}。关闭事务意味着事务内的插入与修改被提交事务上下文随之释放。六、完整执行命令与输出解析在原文档的命令基础上从smokeTests目录执行config 位于该目录$ ./dbsync_test_tool -c config.json -a txnOperation/createTxn.json,txnOperation/inputSyncRowInsertTxn.json,txnOperation/pksGetDeletedRows.json,txnOperation/inputSyncRowModifiedTxn.json,txnOperation/closeTxn.json -o ./output参数说明与 testtool/cmdArgsHelper.h 中的定义一致-c数据库配置文件路径-a逗号分隔的动作文件列表执行顺序即列表顺序-o结果输出目录。注意原文档仅列了 5 个动作文件createTxn → inputSyncRowInsertTxn → pksGetDeletedRows → inputSyncRowModifiedTxn → closeTxn。若想完整验证fullyGetDeletedRows.json所代表的全字段删除行模式可在pksGetDeletedRows.json之后追加该文件即把-a列表扩充为 6 项。这不会破坏事务语义删除行查询是幂等只读操作可在事务关闭前任意位置重复执行。执行完成后./output目录将生成以下产物命名规则见 testtool/Readme.md 与 testtool/action.haction_0.json…action_4.json每个动作对应的返回码文件例如{txn_context:true}、{dbsync_sync_txn_row:0}、{dbsync_get_deleted_rows:0}txn_事务句柄.jsontxnCallback回调落盘的事务数据插入/更新/删除 diff按行追加写入callback.action_id.jsongetDeletedRows等查询动作的回调结果由GetCallbackLogger累积写入。七、底层原理动作分发与 API 调用链理解本用例如何跑起来需要把三层串起来看第一层动作工厂。testtool/factoryAction.h 中的FactoryAction::create根据动作字符串分派——dbsync_create_txn→CreateTransactionActiondbsync_sync_txn_row→SyncTxnRowsActiondbsync_get_deleted_rows→GetDeletedRowsActiondbsync_close_txn→CloseTransactionAction。同一工厂还提供 C 风格动作名如createTxn、syncTxnRow可调用DBSyncTxn的 C 封装接口。第二层C 接口层。各动作最终落到 include/dbsync.h 声明的导出函数。其中dbsync_get_deleted_rows的实现位于 src/dbsync.cpp它会对结果做一次inode字段的 uint64→string 修补FIM 场景下 inode 可能溢出 JSON 数值范围然后经由PipelineFactory::instance().pipeline(txn)-getDeleted(...)走事务管道取出删除 diff 并通过回调返回。第三层事务语义。事务句柄TXN_HANDLE与全局句柄DBSYNC_HANDLE相互独立插入/修改动作必须传事务句柄才能进入事务缓冲区直到dbsync_close_txn才落库提交dbsync_get_deleted_rows则利用事务管道计算数据库中有、而最新快照中已消失的行这正是 Wazuh 各模块向 Manager 上报删除事件的数据来源。八、与单元测试的相互印证事务语义的正确性不只在冒烟测试层面验证接口层单元测试 tests/interface/dbsync_test.cpp 给出了等价的最小复现GetDeletedRowsInvalidInput对空事务句柄调用dbsync_get_deleted_rows应返回非 0验证了参数校验逻辑对应 dbsync.cpp 中if (!txn || !callback_data.callback)分支GetDeletedRowsOnlyPKs先以dbsync_sync_row写入{pid:4,name:System,euser:wazuh}再创建事务、以dbsync_sync_txn_row写入{pid:7,name:Guake}随后dbsync_get_deleted_rows应通过回调返回DELETED且仅含主键{euser:wazuh,name:System,pid:4}的删除行——与冒烟测试pksGetDeletedRows场景完全对应GetDeletedRowsAllAttributes同样流程下回调收到的是包含全部字段的删除行{name:System,pid:4,euser:wazuh}——对应fullyGetDeletedRows场景。两个测试用例验证了同一核心语义事务开启时数据库中的既有行pid4在事务快照中消失后会被dbsync_get_deleted_rows识别为删除。这解释了为什么冒烟测试要在插入两条新行之后调用删除行查询——若数据库原本为空则删除 diff 为空无法验证查询路径。九、总结txnOperation冒烟测试虽只有 15 行文档却完整覆盖了 Wazuh DBSync 事务型数据同步的全部关键 APIdbsync_create_txn开启事务、dbsync_sync_txn_row批量 upsert、dbsync_get_deleted_rows提取删除 diff含仅主键/全字段两种粒度、dbsync_close_txn提交收尾。配合dbsync_test_tool的 JSON 驱动机制与接口层单元测试读者可以将其作为模板自行构造任意表结构的事务同步验证场景或据此理解 Wazuh 内部数据同步管道的差异计算原理。如需继续深入可进一步阅读冒烟测试总览smokeTests/Readme.md测试工具使用说明testtool/Readme.md事务 API 完整声明include/dbsync.h删除行查询实现src/dbsync.cpp接口层测试tests/interface/dbsync_test.cpp【免费下载链接】wazuhWazuh - The Open Source Security Platform. Unified XDR and SIEM protection for endpoints and cloud workloads.项目地址: https://gitcode.com/GitHub_Trending/wa/wazuh创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考