【问题标题】:Using attribute values in other attributes within the same attributes file in chef在厨师的同一属性文件中使用其他属性中的属性值
【发布时间】:2020-01-02 10:18:29
【问题描述】:

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

我的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 主义者看到了所有这些 7.3 并说:“嘿,你为什么不在列表中每个扩展名的值中引用 version 的值?”所以,我在我的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/

我遇到的问题是我不太明白建议的概念将如何发挥作用,因为我的红宝石技能还没有达到标准。

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

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

【问题讨论】:

    标签: ruby chef-infra


    【解决方案1】:

    我不认识 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},它将被替换为每个扩展字符串的值。

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

    # 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) %>
    

    【讨论】:

    • rubocop 建议的另一种方法是使用format,它在技术上相同但更具声明性:format "php-%{version}", { version: "1.2.3" }
    • 同意。我更喜欢format,但主厨文档使用了%,所以我同意了。
    • 你能给我指点厨师文档吗? AFAIK Chef 大量使用cookstyle,即rubocop + 一些厨师特定的规则/修改。 github.com/chef/cookstyle
    • 嘿,我刚刚关闭了 OP 帖子中的链接。如果厨师喜欢格式,格式应该是:)
    • 首先,非常感谢您花时间在如此详细的回复上。我真的很感激,而且解释很清楚。我已经尝试了所有三种方法。我确信这就是答案;但是,使用您提供的任何选项,Chef 在模板中给我一个错误:“Chef::Mixin::Template::TemplateError: key{node[:php][:version]} not found”。也就是说,变量确实可以正确编译:哈希显示在编译的资源中。第一部分显示了关键:变量 {:php=>{"version"=>"7.3"... 所以我有点困惑。再次感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多