在厨师的同一属性文件中的其他属性中使用属性值

Using attribute values in other attributes within the same attributes file in chef

注意:我这里的例子是为了显示我的问题的上下文,而不是真实世界的例子。

我的 attributes/default.rb 文件中有以下示例:

default[:php] = {
    version: '7.3',
    repository: 'ondrej/php',
    extensions: [
        "php7.3",
        "php7.3-common",
        "php7.3-gd",
        "php7.3-mysql",
        "php7.3-curl",
        "php7.3-intl",
        "php7.3-xsl",
        "php7.3-mbstring",
        "php7.3-zip",
        "php7.3-bcmath",
        "php7.3-iconv",
        "php7.3-soap",
        "php7.3-fpm",
        "libapache2-mod-php7.3"
    ],
    options: {
        :timezone => 'America/Los Angeles',
        :memory_limit => '2G',
        :max_execution_time => 1800,
        :zlib_output_compression => 'On',
        :session_save_path => '/var/lib/sessions'
    }
}

接下来,我将其传递给这样的模板:

template '/home/vagrant/php_test.txt' do
    source node['url'] % {version: node['version']}
    source 'php_test.txt.erb'
    owner 'vagrant'
    group 'vagrant'
    mode '0755'
    variables(
        php: node[:php]
    )
end

然后我在模板中引用这些值,如下所示:

PHP Version : <%= @php[:version] %>
PHP Repository : <%= @php[:repository] %>

PHP Extension List:
<% @php[:extensions].each do |extension| %>
<%= "#{extension}" %>
<% end %>

PHP Options List
<% @php[:options].each do |option, value| %>
<%= "#{option}: #{value}" %>
<% end %>

这将生成以下文本文件:

PHP Version : 7.3
PHP Repository : ondrej/php

PHP Extension List:
php7.3
libapache2-mod-php7.3
php7.3-common
php7.3-gd
php7.3-mysql
php7.3-curl
php7.3-intl
php7.3-xsl
php7.3-mbstring
php7.3-zip
php7.3-bcmath
php7.3-iconv
php7.3-soap
php7.3-fpm

PHP Options List
timezone: America/Los Angeles
memory_limit: 2G
max_execution_time: 1800
zlib_output_compression: On
session_save_path: /var/lib/sessions

一切正常;然而,我内心的 DRY-ist 看到了所有那些 7.3 并说,"Hey, why don't you just reference the value of version within the value of each extension in the list?" 所以,我在我的 attributes/default.rb 文件中尝试这个:

...

extensions: [
    "php#{node[:php][:version]}",
    "php#{node[:php][:version]}-common",
    "php#{node[:php][:version]}-gd",
    "php#{node[:php][:version]}-mysql",
    "php#{node[:php][:version]}-curl",
    "php#{node[:php][:version]}-intl",
    "php#{node[:php][:version]}-xsl",
    "php#{node[:php][:version]}-mbstring",
    "php#{node[:php][:version]}-zip",
    "php#{node[:php][:version]}-bcmath",
    "php#{node[:php][:version]}-iconv",
    "php#{node[:php][:version]}-soap",
    "php#{node[:php][:version]}-fpm",
    "libapache2-mod-#{node[:php][:version]}"
]

...

这有(至少)两个问题。首先,它没有达到我的预期。当我遍历模板中的数组时,每个值都打印为字符串而不是插值。其次,它打破了这里提到的厨师最佳实践:https://github.com/pulseenergy/chef-style-guide#attributes

那么,在另一个群体中使用一个属性值的最佳方式是什么?

在思考这个问题时,我想到了两个方案:

  1. 按此处所示使用延迟插值: https://coderanger.net/derived-attributes/

我的问题是我不太明白建议的概念是如何工作的,因为我的 ruby 技能没有达到标准。

  1. 存储没有 php- 后缀的扩展,然后在配方中循环它们并将 php、版本字符串和扩展连接成每个扩展的单个值。将每个存储在一个新数组中,该数组传递给模板。

还有其他方法可以实现吗?可能通过强制 "php{node[:php][:version]}" 属性插入模板?

我不了解 Chef,但阅读最佳实践页面,通过延迟插值派生属性是这里的正确方法。它应该相当简单:

extensions: [
  "php%{version}",
  "php%{version}-common",
  "php%{version}-gd",
  # ...
]

稍后,当您渲染它时:

<% @php[:extensions].each do |extension| %>
<%= extension % @php %>
<% end %>

这有点不明显,但它有效,因为 string % hash 将使用 hash 中的键替换字符串中的任何命名占位符。不作为命名占位符存在的哈希值将被忽略。

"test: %{bang}" % {baz: "bin", bang: "bar"}
=> "test: bar"

由于您的 @php 变量有一个 :version 键,如果该字符串包含占位符 %{version},它将在呈现时被替换到每个扩展字符串的值中。 =19=]

你也可以更明确地做到这一点:

# Create a hash with the one key:
<%= extension % {version: @php[:version]} %>

# Or, just create a hash by slicing out just the attribute you care about
<%= extension % @php.slice(:version) %>