Chef自定义资源:仅在文件更新时触发通知的实现方法
问题:自定义资源仅在文件更新时触发Apache重载
我不确定自己是否正确理解了基于自定义资源触发其他资源的概念。我有如下虚构的自定义资源:
get_api_calls 'www.myapi.com' do request '<myrequest>' target_path '/<my>/<target>/<filepath>' notifies :reload, 'service[apache]', :delayed end
该资源的底层逻辑是调用API、下载所需文件并存储到目标路径。但每次执行这段Chef代码时,都会重载Apache。我希望仅当文件从API下载并更新时,才触发Apache的重载,就像file资源那样仅在文件变更时触发通知。请问如何为我的资源实现该行为?
解决方案
要实现这个效果,核心是让你的自定义资源仅在实际更新了目标文件时,才标记自身为"已更新"状态——Chef的通知系统只会在资源被标记为更新时,触发对应的notifies/subscribes动作。
具体需要在自定义资源的提供者(Provider)代码里做以下处理:
- 对比文件变更:在下载文件前后,通过校验和(如SHA256)或内容对比,判断目标文件是否发生变化。
- 控制更新标记:根据对比结果,调用
updated_by_last_action方法手动标记资源是否更新。
简化的提供者代码示例
class Chef class Provider class GetApiCalls < Chef::Provider def action_run # 1. 从API获取文件内容并写入临时文件 api_content = fetch_api_content(new_resource.request) temp_file_path = '/tmp/api_download.tmp' File.write(temp_file_path, api_content) # 2. 计算新旧文件的SHA256校验和 target_exists = File.exist?(new_resource.target_path) target_checksum = target_exists ? Digest::SHA256.file(new_resource.target_path).hexdigest : nil new_checksum = Digest::SHA256.file(temp_file_path).hexdigest if target_checksum != new_checksum # 3. 文件有变更,替换目标文件并标记资源更新 FileUtils.mv(temp_file_path, new_resource.target_path) updated_by_last_action(true) else # 文件无变更,删除临时文件并标记无更新 File.delete(temp_file_path) updated_by_last_action(false) end end private def fetch_api_content(request) # 这里实现调用API获取内容的逻辑 # 示例:Net::HTTP.get(URI(new_resource.name + request)) end end end end
关键细节说明
- 校验和对比:用哈希值对比比直接读取文件内容更高效,尤其适合大文件场景。
updated_by_last_action方法:这是Chef资源的核心控制方法,默认自定义资源可能会被标记为"总是更新",必须手动根据实际变更情况设置状态。- 边界场景处理:要覆盖目标文件不存在的首次下载场景,此时也需要标记资源为更新,触发Apache重载。
修改后,只有当API下载的文件与目标路径文件存在差异时,get_api_calls资源才会触发Apache的重载动作,和file资源的行为完全一致。
内容的提问来源于stack exchange,提问作者Pegasus1985
相关产品推荐
相关产品推荐

