【问题标题】:With Chef, how to execute "resource 1" before "resource 2", conditional on "resource 2" executing?使用 Chef,如何在“资源 2”之前执行“资源 1”,以执行“资源 2”为条件?
【发布时间】:2015-03-19 01:39:38
【问题描述】:

我有一本包含多个食谱的 Chef 食谱,它安装了一项服务。 chef-client 的工作方式,它每 15 分钟(或其他定期间隔)重新收敛。现在我的食谱的第一步是停止服务,所以服务将每 15 分钟停止一次,但我真的想避免这种情况。问题是需要停止服务才能执行某些步骤。

如果我的食谱资源中只有一两个条件,我可以这样做:

condition1 = ... # some true/false values
condition2 = ... #

service myservice do
  only_if { condition1 or condition2 }
  action :stop
end

resource1 do
  only_if { condition1 }
end

resource2 do
  only_if { condition2 }
end

但由于我有十几个条件,在多个食谱中,它变得不优雅。有没有办法做到这个伪代码的作用?

service_resource = service myservice do
  # somehow don't execute this right now, but wait for
  # signal from resource1 or resource2
  action :stop
end

resource1 do
  make sure service_resource executed first
  only_if { condition1 }
end

resource2 do
  make sure service_resource executed first
  only_if { condition2 }
end

如果 Chef 中有一些“通知 :before”机制(而不是例如“通知 :immediately”),我可以使用它,但我没有找到任何类似的东西。有什么想法吗?

编辑:

在考虑了更多之后,另一种方法仍然不是完美但更好,它是通过定义一个被覆盖的属性来利用 Chef 的编译阶段。这样至少我们不必将所有条件保存在一个地方。

# in an "attributes" file:
default["stop_service"] = false

# in some recipe:
service myservice do
  action :stop
  only_if { node["stop_service"] }
end

# ... later, or in some other recipe file
condition1 = ... # true/false
if condition1
  # I think this executes before the only_if of the "service" resource
  override["stop_service"] = true
end

resource1 do
  only_if { condition1 }
end

【问题讨论】:

  • 类 UNIX 操作系统上的大多数服务都可以在实时更新其配置(甚至代码,只要本地包管理器通过创建新 inode 而不是重写现有 inode 以获取新内容来替换文件)更新,这就是为什么这不是一个常见问题的原因——大多数时候,在重新配置或升级之前不需要停止服务。
  • @CharlesDuffy 最后也许这就是我所依赖的,但我写的实际上是一个简化:我们有一堆服务,我不确定它们是否都能拥有他们的运行时配置更改。我认为其中至少有一个会自动重新加载其配置,因此它可以在仅应用部分更改的情况下重新加载。此外,对于某些配方,我们在现有文件中追加/替换,因此在这些情况下,我们没有使用新的 inode(如果我理解正确的话)。
  • 取决于附加/替换功能的工作方式——安全实现(当附加的数据超过一个系统调用,或者需要任何就地编辑时)通过编写一个同一目录中的临时文件并将其重命名为目标。但是,是的,如果您希望这些更改是原子的,修改多个文件并实现自动重新加载行为,那么您希望围绕配置更改重新启动(或 SIGSTOP 和 SIGCONT,如果支持)是有道理的。跨度>
  • 其实我没有意识到,但你是对的。大多数时候,我们使用“sed -i”(“inplace”,我刚刚读到,它按照您的描述进行)。在其他一些情况下,我们使用 Chef::Util:FileEdit,它不会完全按照您的描述进行操作,但会保留旧文件的备份,因此旧的 inode 仍然保持不变(我认为)。

标签: chef-infra chef-recipe


【解决方案1】:

我会做什么:

将配置暂存到一个“暂存”的地方,如果这个改变,通知停止,复制文件,启动服务。

大致意思:

service "my_service" do 
  action :nothing
end

template "/staging/conf1" do
  [... usual attributes ...]
  notifies :stop,"service[my_service]",:immediately
end

template "/staging/conf2" do
  [... usual attributes ...]
  notifies :stop,"service[my_service]",:immediately
end

remote_file "/opt/my_service/etc/conf1" do
  source "/staging/conf1"
  notifies :start,"service[my_service]" # delayed here to allow all conf files to be updated.
end

remote_file "/opt/my_service/etc/conf2" do
  source "/staging/conf2"
  notifies :start,"service[my_service]" # delayed here to allow all conf files to be updated.
end

我个人的喜好是循环遍历文件/模板定义哈希,以使用相同的资源,例如:

node['my_namespace']['conf_files']['conf1'] = "template1"
node['my_namespace']['conf_files']['conf2'] = "template2"

然后循环使用

node['my_namespace']['conf_files'].each do |cfgfile,tmplname|
  template "/staging/#{cfgfile}" do
     source tmplname
     notifies :stop,"service[my_service]",:immediately
  end

  remote_file "/opt/my_service/etc/#{cfgfile}" do
    source "/staging/#{cfgfile}"
    notifies :start,"service[my_service]"
  end
end

对于更复杂的用例,您也可以使用哈希而不是单个值

如果涉及的资源超过 2 个(执行 conf 文件的特定命令以在替换实际资源之前对其进行验证等),则可能适合定义。

另一种可能是在 LWRP 的 load_current_resource 中完成所有暂存工作,但对于所描述的用例来说,我可能走得太远了。

【讨论】:

  • 谢谢@Tensibai。我认为它可能适用于某些类型的资源,但它确实会影响食谱的结构。我试图避免如此大的变化并尽可能保持食谱“自然”,这就是为什么我正在寻找类似“通知:之前”之类的东西(这需要“厨师资源队列”的一些魔法......但如果它不在框架中,那就没什么可做的了)。
  • @fsdj 好吧,这个案子已经在Here 进行了讨论,并进行了一些试验。票中链接的 PR 上的评论说明了为什么它实际上不在 Chef 中。
  • 哦,哇,这正是我的意思。所以,是的,我想目前在 Chef 中确实 可行(正如 PR 所说,“没有大的重构”)。资源之间的“依赖”会更好(以避免多次运行上一步,就像有人提到的那样)。非常感谢,这将避免进一步无用的挖掘。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多