You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chef运行中先生成文件名再下载S3备份的方案咨询

解决Chef中生成文件名后再执行S3下载的问题

这个问题我之前也碰到过,核心是Chef的**编译阶段(Compile Phase)和收敛阶段(Converge Phase)**的执行顺序差异搞的鬼,咱们一步步拆解解决:

问题根源

你当前的代码里,ruby_block的逻辑是在收敛阶段才会执行,但aws_s3_file资源的remote_path属性会在编译阶段就被解析求值——这时候latest_backup变量不仅还没被赋值,而且它是ruby_block内部的局部变量,外部资源根本访问不到,所以才会抛出undefined method 'latest_backup'的错误。

另外还要注意你原代码里的时间条件逻辑有问题:(utc_now > utc_midday ) && (utc_now < utc_midnight)这个判断永远不会成立(utc_midday是22点,utc_midnight是10点,时间不可能同时大于22点又小于10点),得先修正这个逻辑漏洞。

最佳解决方案

方案1:编译阶段直接计算文件名(推荐,最简单高效)

如果文件名的生成不需要依赖收敛阶段的资源状态(比如不需要先检查某个文件是否存在),直接在编译阶段计算文件名是最优选择,这样aws_s3_file可以直接使用变量:

require 'time'

utc_now = Time.now.utc
current_date = utc_now.strftime("%Y%m%d")
utc_midnight = Time.new(utc_now.year, utc_now.month, utc_now.day, 10, 00, 1).utc
utc_midday = Time.new(utc_now.year, utc_now.month, utc_now.day, 22, 00, 1).utc

if utc_now > utc_midnight && utc_now < utc_midday
  # 当天10:00:01到22:00:00之间,使用当天的-00001.tgz
  latest_backup = "data_#{current_date}-00001.tgz"
elsif utc_now >= utc_midday
  # 当天22:00:01到次日10:00:00之间,使用当天的-120001.tgz
  latest_backup = "data_#{current_date}-120001.tgz"
else
  # 当天00:00:00到10:00:00之间,使用前一天的-120001.tgz
  previous_date = (utc_now - 86400).strftime("%Y%m%d")
  latest_backup = "data_#{previous_date}-120001.tgz"
end

aws_s3_file "/root/backup.tgz" do
  remote_path "backup-dir/#{latest_backup}"
  bucket "my-backups-bucket"
  region "ap-southeast-2"
end

方案2:收敛阶段生成文件名(适合依赖收敛状态的场景)

如果必须在收敛阶段生成文件名(比如需要先执行某些资源后才能确定文件名),可以用node.run_state临时存储变量,配合lazy属性延迟remote_path的求值:

ruby_block "generate file name" do
  block do
    require 'time'
    utc_now = Time.now.utc
    current_date = utc_now.strftime("%Y%m%d")
    utc_midnight = Time.new(utc_now.year, utc_now.month, utc_now.day, 10, 00, 1).utc
    utc_midday = Time.new(utc_now.year, utc_now.month, utc_now.day, 22, 00, 1).utc

    if utc_now > utc_midnight && utc_now < utc_midday
      node.run_state[:latest_backup] = "data_#{current_date}-00001.tgz"
    elsif utc_now >= utc_midday
      node.run_state[:latest_backup] = "data_#{current_date}-120001.tgz"
    else
      previous_date = (utc_now - 86400).strftime("%Y%m%d")
      node.run_state[:latest_backup] = "data_#{previous_date}-120001.tgz"
    end
  end
  action :create
end

aws_s3_file "/root/backup.tgz" do
  # 使用lazy块延迟到收敛阶段求值remote_path
  remote_path lazy { "backup-dir/#{node.run_state[:latest_backup]}" }
  bucket "my-backups-bucket"
  region "ap-southeast-2"
  # 确保S3下载在文件名生成之后执行
  subscribes :create, 'ruby_block[generate file name]', :immediately
end

这里node.run_state是Chef用来临时存储运行时数据的容器,不会持久化到节点属性中,非常适合这种临时变量的场景;lazy块会推迟属性的求值到收敛阶段,这时候node.run_state[:latest_backup]已经被赋值了。

内容的提问来源于stack exchange,提问作者never_odd_or_even

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:21:16