如何让puppet-mongodb模块在puppet-agent运行时上报Mongo Shell错误?
问题本质
这个模块执行mongo/mongosh客户端命令时,没做退出码校验,也没捕获错误输出——哪怕MongoDB返回明确错误(比如数据库名大小写冲突),Puppet也会误以为操作成功。
可行修复方案
1. 给模块打临时补丁
找到模块里的provider文件(比如lib/puppet/provider/mongodb_database.rb、lib/puppet/provider/mongodb_user.rb),修改命令执行逻辑,强制校验错误:
以创建数据库的代码为例,修改create方法:
def create command = "mongosh admin --eval 'db.getSiblingDB(\"#{resource[:name]}\").createCollection(\"dummy\")' --quiet" # 强制让Puppet在命令失败时抛出错误,同时合并stderr到stdout result = execute(command, :failonfail => true, :combine => true) # 额外检查输出里的错误关键词,覆盖部分退出码为0但实际失败的情况 if result.match?(/error|failed/i) fail("MongoDB创建数据库失败: #{result}") end end
核心改动:
- 加
:failonfail => true:命令退出码非0时直接触发Puppet错误 - 加
:combine => true:把错误输出合并到标准输出,方便捕获 - 手动检查输出中的错误关键词,避免漏判
2. 升级到模块最新稳定版
先查voxpupuli的仓库,看看有没有已经合并的错误修复PR,或者发布了新版本。直接升级可能最快解决问题:
puppet module upgrade voxpuli-mongodb
3. 自己写自定义资源(长期替代)
如果模块维护不及时,不如自己写个轻量的自定义资源,确保错误能被正确捕获:
先定义资源类型(lib/puppet/type/mongodb_custom_db.rb):
Puppet::Type.newtype(:mongodb_custom_db) do ensurable newparam(:name) do isnamevar end # 按需加连接地址、认证参数等 end
再写对应的provider(lib/puppet/provider/mongodb_custom_db.rb):
Puppet::Type.type(:mongodb_custom_db).provide(:mongosh) do def create cmd = "mongosh admin --eval 'db.getSiblingDB(\"#{resource[:name]}\").createCollection(\"dummy\")'" output = `#{cmd} 2>&1` exit_code = $?.exitstatus if exit_code != 0 || output.include?("error") raise Puppet::Error, "创建数据库#{resource[:name]}失败: #{output}" end end def destroy cmd = "mongosh admin --eval 'db.getSiblingDB(\"#{resource[:name]}\").dropDatabase()'" output = `#{cmd} 2>&1` exit_code = $?.exitstatus if exit_code != 0 || output.include?("error") raise Puppet::Error, "删除数据库#{resource[:name]}失败: #{output}" end end def exists? cmd = "mongosh admin --eval 'db.getSiblingDB(\"#{resource[:name]}\").stats()' --quiet" output = `#{cmd} 2>&1` $?.exitstatus == 0 && !output.include?("error") end end
用这个自定义资源替代原模块的mongodb_database,只要MongoDB命令出错,Puppet会立刻报错并终止,同时输出具体错误信息。
4. 加个校验用的exec临时凑活
如果不想改模块或写自定义资源,就在catalog里加个exec,手动验证操作结果:
$db_name = lookup('mongodb::databases::my_db') exec { "verify_db_${db_name}": command => "mongosh admin --eval 'db.getSiblingDB(\"${db_name}\").stats()' | grep -q 'ok' && exit 0 || exit 1", path => ['/usr/bin', '/usr/local/bin'], require => Mongodb_database[$db_name], }
这个exec会在数据库创建后检查是否真的存在,不存在就会报错,让Puppet显示失败状态。
验证方式
把Hiera里的数据库名改成全大写,跑puppet agent -t,如果修复生效,Puppet会抛出MongoDB的大小写冲突错误,而不是显示“已创建”。
内容的提问来源于stack exchange,提问作者Aleksandr Makhov

