首页 > 解决方案 > 基于 Chef 版本的 Cookbook 依赖项

问题描述

我有一个包装食谱,它使用来自其他食谱的资源,但它们有不同的限制。我尝试定义我的 metadata.rb 如下:

name 'yp_linko'
maintainer 'The Authors'
maintainer_email 'devops@yp.ca'
license 'all_rights'
description 'Installs/Configures yp_linko'
long_description 'Installs/Configures yp_linko'
version '1.3.4'

depends 'apt'
if chef_version '<= 12' then
  depends 'ypg_tomcat'
else
  depends 'yp_tomcat'
end

这不起作用,因为厨师在收敛期间抓住了两本食谱。我尝试了几种不同的语法(only_if、unless 等),但都没有奏效。任何人都有解决这个问题的想法?

标签: rubychef-inframetadatachef-recipe

解决方案


TL;博士

您正在使用 Chef DSL 中的约束,但它并不打算使用。您需要基于布尔表达式而不是元数据约束进行分支。我提供了几种使用String#to_f作为示例的方法(如果您关心语义版本控制中的补丁级别,则不推荐),以及更准确但经常被忽视的Gem::Version

不要使用约束进行分支

if chef_version '<= 12'

您正在尝试使用来自 DSL 的约束。这个约束有一个特定的目的:声明食谱支持的 chef-client 版本,而不是提供逻辑分支。如果不查看 DSL 的底层 Chef 代码,我会说表达式不太可能以您期望的方式提供 if-then 表达式。暂时不管这是否是正确的模式,您可以尝试以几种不同的方式获取当前版本的 Chef 工具:

  1. 在厨师客户端版本上分支,可能转换为浮点数(通常是字符串)。例如:

    if Chef::VERSION.to_f <= 12
    
  2. 从 ohai 获取节点值,例如:

    if node['chef_packages']['chef']['version'].to_f <= 12
    
  3. 直接从客户端解析值,例如:

    depends %x(chef-client --version).split[1].to_f <= 12 ? 'ypg_tomcat' : 'yp_tomcat'
    

但是,在所有情况下,您都必须处理这样一个事实,即传递给您的是一个包含语义版本控制的字符串,而不是浮点数或整数。因此,您必须弄清楚您真正想要如何解析信息,这可能容易出错(不过,请参阅下面的使用 Gem::Version 的技巧)。在任何情况下,一旦你按照你想要的方式解析它,你就可以使用比较运算符来匹配它以获得你想要的分支行为。

更好的选择

与其试图让元数据约束保持业务逻辑,不如将数据移出到属性中。考虑一个属性,例如node['yp_linko']['tomcat_cookbook'],您可以根据除语义版本控制之外的一些其他可检测节点值来设置该属性。

另一种方法是声明两本食谱为依赖项,然后在yp_linko食谱中包含您想要的食谱。例如,假设您没有在 Tomcat 食谱中声明不兼容的 chef-client 版本:

# metadata.rb
depends 'yp_tomcat'
depends 'ypg_tomcat'

# default.rb
if Chef::VERSION <= Gem::Version.new(12)
  include ypg_tomcat::default
else
  include yp_tomcat::default
end

最后,您应该首先考虑在基础设施中运行不同版本的 Chef 客户端是否真的有意义。可能有业务需要这样做,但这是您实际上要解决的真正问题。在你的食谱中分支是基础设施问题的 X/Y 解决方案。您似乎可能还有其他具有类似问题的食谱,因此至少值得考虑让所有客户使用相同版本而不是在食谱级别解决问题是否更有意义。


推荐阅读