3

我想检查节点属性的值。这个case声明是我迄今为止所拥有的,它有效:

case node[:languages][:ruby][:host_cpu]
   when "x86_64"
   ...
   when "i686"
   ...
end

我想做的是改用if语句。这是我尝试过的:

if node[:languages][:ruby][:host_cpu]?("X86_64")
   ...
end

这是基于以下内容,哪个有效。

if platform?("ubuntu")
    ...
end

然而,我的尝试没有奏效。它在行上给出了一个语法错误,if说有一个意外\n并且$end是预期的。

我发现有两种执行if. 第一个是我在上面演示的,它(显然)只适用于资源,并且if_only适用于节点。像这样

if_only {node[:languages]} 

这似乎仅适用于检查节点的存在,并且在 do 上下文中。

如何使用if语句检查节点的值?一种方法确实检查值,但仅检查资源,另一种方法检查节点,但仅检查它们的存在,而不检查它们的值。

4

1 回答 1

8

您正在混合使用许多不同的条件变体,其中大部分是 Chef 的一部分,而不是 Ruby。让我尝试一一描述不同的选项。

通常,acase大致相当于一系列ifandelsif语句。你的case上面

case node[:languages][:ruby][:host_cpu]
   when "x86_64"
   ...
   when "i686"
   ...
end

因此大致相当于

if node[:languages][:ruby][:host_cpu] == "x86_64"
  ...
elsif node[:languages][:ruby][:host_cpu] == "i686"
  ...
end

附带说明一下,case实际上使用的===运算符通常不是可交换的,但功能更强大。对于简单的比较,它的工作原理与此相同==。这两种变体都是 Ruby 语言的一部分,您可以在其中编写食谱。

您提到的其他选项实际上是 Chef 在 Ruby 之上定义的 API 的一部分。这通常被称为 Chef DSL(代表域特定语言,即语言的扩展或改编,在这种情况下 Ruby 用于特定使用域,在这种情况下是配置管理。)

platform?方法是 Chef 定义的一种方法,用于检查当前平台是否是传递的值之一。您可以阅读更多相关信息(以及类似的方法,例如platform_family?Chef docs 现在推荐的用于一般食谱的方法和一些常用的 ruby​​ idioms

附带说明一下:您可能会惊讶于 Ruby 允许?!字符出现在方法名称的末尾,这使得 Ruby 在这方面的类似语言中相当独特。这些字符只是方法名称的一部分,对语言没有特殊意义。它们仅按惯例用于程序员以更好地识别方法的目的。如果一个方法?的末尾有一个,它将用于检查某些条件,并期望返回一个真值或假值。以 a!结尾的方法通常会执行一些潜在的危险操作,例如更改对象、删除内容……同样,这只是一个约定,不会被语言解释。

您提到的最后一个选项,only_ifand 通过扩展not_if用于定义 Chef 资源的条件,以确保它们仅在某个条件为真时(或使用时not_if,如果为假)执行。由于这些属性仅用于 Chef 资源,它们自然也由 Chef 定义。

要了解它们为何有用,有必要了解 Chef 运行的工作原理。详细信息可以在Chef Run 的解剖描述中找到。重要的是,您基本上有两个执行阶段:资源编译和收敛。第一步,执行定义资源的实际代码。在这里,您的case语句中的代码也将运行。在加载了所有配方并定义了所有资源后,Chef 进入第二阶段,即收敛阶段。在那里,执行更改的资源的实际实现(创建文件和目录,安装包,...)运行。只有在这个阶段,才会检查only_ifnot_if条件。

其实你可以观察到两者的区别

file "/tmp/helloworld"
  action :create
  content "hello world"
end   

if File.exist?("/tmp/helloworld")
  file "/tmp/foobar"
    action :create
    content "foobar"
  end
end

file "/tmp/helloworld"
  action :create
  content "hello world"
end   

file "/tmp/foobar"
  action :create
  content "foobar"
  only_if{ File.exist?("/tmp/helloworld") }
end

在第一个变体中,/tmp/foobar在资源编译期间检查条件是否存在。此时,实际创建/tmp/helloworld文件的代码尚未运行,因为它仅在转换步骤中运行。因此,在您第一次运行期间,/tmp/foobar不会创建该文件。

然而,在第二个变体中,检查是only_if在转换期间进行评估的。在这里,您会注意到这两个文件都是在第一次运行时创建的。

如果您想了解更多关于 Ruby 中条件的定义是如何工作的(而且您绝对应该),您可以阅读Ruby Blocks,它们或多或少是可以传递以供以后执行的代码片段。

于 2013-01-05T11:39:16.453 回答