【问题标题】:Compile time vs. run time in Chef recipesChef 食谱中的编译时间与运行时间
【发布时间】:2014-11-16 19:36:30
【问题描述】:

我有一个名为 java 的(简化的)配方,当然可以安装 Java。

文件 recipes/default.rb

include_recipe "install_java"

文件配方/install_java.rb

# Install RPM from yum repo via yum_install library function
yum_install("jdk1.7.0_51")

# List the directories in /usr/java
jdk_dir = `ls -ld /usr/java/jdk1.* | sort | tail -1`
if jdk_dir.empty?
  raise "Missing JDK installation"
end

当我通过“chef-client -o recipe[java]”运行食谱时

Synchronizing Cookbooks:
  - java
Compiling Cookbooks...
ls: /usr/java/jdk1.*: No such file or directory

================================================ ============================= /var/chef/cache/cookbooks/java/recipes/default.rb 中的配方编译错误 ============================== ==============================================

RuntimeError
------------
Missing JDK installation

似乎没有调用 yum_install() 函数。但是,如果我将 install_java.rb 配方修改为只有

# Install RPM from yum repo via yum_install library function
yum_install("jdk1.7.0_51")

它有效。

这是为什么?

【问题讨论】:

    标签: chef-infra


    【解决方案1】:

    所以我不能完全确定,但很可能yum_install 是一种资源(或某种创建资源的助手)。配方有效地分两次运行。首先执行每个文件(字面意思是通过 Ruby 的exec)。当在 DSL 中创建资源时,它“编译”为内存中的资源对象,该对象被添加到全局资源集合(所有资源的大数组)中。编译完所有配方文件后,Chef 会遍历资源集合并根据请求运行每个资源的操作(如果需要,在中间发送通知)。

    总而言之,这意味着yum_install 行在运行时可能实际上并没有做任何事情,除了将对象推入数组之外。您可以将其他代码包装在 ruby_code 块中以将其延迟到收敛时间。

    【讨论】:

    • 谢谢。将其余代码包装在 ruby​​_block 中就可以了。
    【解决方案2】:

    好的,因此 Chef 运行需要两次传递。

    “编译时间”

    我喜欢将此称为收集阶段
    此时,您的配方中的实际 ruby​​ 代码已运行。这意味着任何陈述,如 jdk_dir = ls -ld /usr/java/jdk1.* | sort | tail -1 将在那个时候被执行。但是,创建 Chef 资源 yum_install("jdk1.7.0_51") 的 ruby​​ 代码仅创建资源。这些资源由您的食谱代码创建,然后被添加到 Chef resource_collection,但资源操作尚未运行。

    “收敛时间”

    我称之为解决阶段。 在这一点上 - 在所有配方运行(创建资源,但不运行操作)之后 - 我们现在准备好实际运行资源操作。 Chef 从 resource_collection 中的第一个资源开始,并对该资源运行指定的操作。它通过集合工作,根据需要调用通知,直到所有资源的操作都已运行。然后你的运行就完成了。

    您的具体情况

    因此,在您的情况下,您尝试在 收集阶段 访问目录,但直到 解决阶段 才创建目录。如果您想在解析阶段运行 ruby​​ 代码,您可以在 ruby_block 资源中执行此操作。例如:

    ruby_block 'verify java is there' do
      block do
        if jdk_dir.empty?
          raise "Missing JDK installation, reinstall"
        end
      end
    end
    

    如果这个ruby_block资源被放置在你的yum_install(应该是yum_package)资源之后,那么它将被放置在collection_phase中的安装资源之后,然后被执行在 Chef 运行的解决阶段(即运行时间)。

    【讨论】:

    • 正是我正在寻找的那种解释!谢谢!
    【解决方案3】:

    最好的办法是使用统一模式编写自定义资源,而不是配方:

    资源/install_java.rb:

    unified_mode true
    provides :install_java
    
    action :install do
      # Install RPM from yum repo via yum_install library function
      yum_install("jdk1.7.0_51")
    
      # List the directories in /usr/java
      jdk_dir = `ls -ld /usr/java/jdk1.* | sort | tail -1`
      if jdk_dir.empty?
        raise "Missing JDK installation"
      end
    end
    

    食谱/default.rb:

    install_java  "install my java -- you could make this name_property the version"
    

    统一模式消除了编译/收敛两阶段解析,因此它可以工作,但必须将代码移动到自定义资源(这会带来额外的可用性优势并且无论如何都是最佳实践 - 现在资源可以增长属性和可以重复使用安装不同版本的java等)。

    【讨论】:

      猜你喜欢
      • 2015-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 2023-03-25
      相关资源
      最近更新 更多