等待资源完成:Chef Recipe中资源执行异常触发问题问询
这个问题本质是Chef的资源执行逻辑导致的:每个资源的条件判断(比如only_if)是独立评估的,不会自动关联前面资源的执行状态。哪怕custom_resource1执行失败,只要目标文件已经存在(比如之前执行过、或者custom_resource1部分执行后创建了文件但最终报错),log资源的only_if就会满足,进而触发custom_resource2。
下面给你几个针对性的解决方案,你可以根据自己的场景选择:
1. 让custom_resource1失败直接终止整个Chef Run
如果custom_resource1是核心依赖,它失败后整个部署就没有意义,那最简单的方式是让它失败后立刻停止Chef运行,这样后续的log和custom_resource2都不会执行。
修改custom_resource1的代码:
custom_resource1 "example" do # 你的原有配置(遍历data_bags、写入文件等) ignore_failure false # 默认就是false,明确声明更清晰 retries 0 # 关闭重试,失败就立刻终止 end
当custom_resource1执行失败时,Chef会直接抛出异常并终止整个Run,后面的资源根本不会被评估和执行,自然不会触发custom_resource2。
2. 给log资源添加依赖custom_resource1成功的条件
如果你希望Chef Run继续执行其他资源,但只有当custom_resource1成功完成时才触发custom_resource2,可以给log资源增加一个判断custom_resource1执行状态的条件:
log 'File found!' do message "Found it" level :info notifies :run, 'custom_resource2[example]', :immediately # 保留原有的文件存在判断 only_if { ::File.exists?(file) } # 新增:检查custom_resource1是否成功执行并完成更新 only_if { resources('custom_resource1[example]').updated_by_last_action? } end
resources('custom_resource1[example]').updated_by_last_action?会检查custom_resource1是否在本次Run中成功执行并产生了变更。如果custom_resource1执行失败,这个条件会返回false,log资源就不会执行,也就不会触发custom_resource2。
3. 把custom_resource2的触发逻辑整合到custom_resource1内部
如果你有权限修改custom_resource1的定义,最直接的方式是把custom_resource2的调用放到custom_resource1的成功分支里,确保只有当custom_resource1所有步骤执行完成后才触发它:
# 假设这是custom_resource1的资源定义 action :create do # 原有遍历data_bags、写入文件的逻辑 # ...(这里是你的核心代码) # 只有当上面的代码全部成功执行后,才调用custom_resource2 custom_resource2 "example" do action :run # 可以根据需要添加额外条件 end end
这样如果custom_resource1中间执行失败抛出异常,后面调用custom_resource2的代码根本不会运行,从根源上避免了误触发。
内容的提问来源于stack exchange,提问作者hfskappel

