Chef 和 ruby​​ 模板 - 如何遍历键值对?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11490781/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 05:17:50  来源:igfitidea点击:

Chef and ruby templates - how to loop though key value pairs?

rubychef

提问by Tampa

1) I have a data bag as follows:

1)我有一个数据包如下:

 "zookeeper":{
        "server1":"111.111.111.111",
        "server2":"222.222.222.222"
        },

2) In my recipe I get the hash as follows.

2)在我的食谱中,我得到如下哈希值。

data_bag("mydb")
db = data_bag_item("mydb", "rtb")
ZOOKEEPER = db['zookeeper']

3) Also in my recipe I have a template as follows:

3)同样在我的食谱中,我有一个模板如下:

template "/etc/zookeeper/conf/zoo.cfg" do
  path "/etc/zookeeper/conf/"
  source "zoo.cfg.erb"
  owner "root"
  group "root"
  mode "0644"
 variables :zookeeper => #{ZOOKEEPER}
end

4) I need to have my template look like this

4)我需要让我的模板看起来像这样

server.1=111.111.111.111:2888:3888
server.2=222.222.222.222:2888:3888

My question is this. How do I pass the hash to the template so I can loop through the hash and create the temlplate? I am not a strong ruby coder.

我的问题是这个。如何将哈希传递给模板,以便我可以遍历哈希并创建模板?我不是一个强大的 ruby​​ 编码器。

for example:

例如:

count = 1
for server, ipaddress in zookeeper:
      server.count=ipaddress:2888:3888
      count = count + 1

回答by Holger Just

There are some slight inconsistencies in your setup. In your data bag, you assign IP addresses a name (by using a hash in your JSON). However, you don't seem to use the name in your generated template at all. This has some implications which you should be aware of:

您的设置存在一些轻微的不一致。在您的数据包中,您为 IP 地址分配一个名称(通过在 JSON 中使用哈希)。但是,您似乎根本没有在生成的模板中使用该名称。这有一些您应该注意的含义:

When using associative arrays (called hashes in Ruby or objects in Javascript), the order of the elements is generally not preserved and can significantly change when adding additional elements. While some effort is done on Ruby 1.9 to preserve the insertion order when looping over the hash, you shouldn't generally rely on that. This leads to two possible alternatives to improving your data bag. Which one to choose depends on your actual use case:

当使用关联数组(在 Ruby 中称为散列或在 Javascript 中称为对象)时,元素的顺序通常不会保留,并且在添加其他元素时可能会发生显着变化。虽然在 Ruby 1.9 上做了一些努力来在循环哈希时保留插入顺序,但您通常不应该依赖它。这导致了两种可能的替代方法来改进您的数据包。选择哪一个取决于您的实际用例:

  • Use an array instead of the hash. In an array, the order is guaranteed to be kept. If you don't use the name anyway (i.e. the key in your original hash), you can simply use a hash and be safe here. When going this road, we can loop over the array in the template and generate the count from that.
  • If the order doesn't matter, you should use the key in the hash to name the server as generated into your template. Right now, you use server<Number>in your data bag but server.<Number>in your template. That way, we can use the key to name your servers and possibly override the generated names.
  • 使用数组而不是散列。在数组中,顺序保证被保留。如果您无论如何都不使用该名称(即原始散列中的键),您可以简单地使用散列并且在这里是安全的。走这条路时,我们可以遍历模板中的数组并从中生成计数。
  • 如果顺序无关紧要,您应该使用散列中的键来命名在模板中生成的服务器。现在,您server<Number>在数据包中使用但server.<Number>在模板中使用。这样,我们可以使用密钥来命名您的服务器并可能覆盖生成的名称。

Using an Array

使用数组

When using the array in your data bag, i.e. when you have something like this:

当使用数据包中的数组时,即当你有这样的东西时:

"zookeeper": [
  "111.111.111.111",
  "222.222.222.222"
],

you can loop over the array like this in your template:

您可以在模板中像这样循环遍历数组:

<% @zookeeper.each_with_index do |ipaddress, index| %>
<%= "server.#{index}=#{ipaddress}:2888:3888" %>
<% end %>

This used the ERB template languageto create your file. It used the each_with_indexmethod to iterate over each element in the array.

这使用ERB 模板语言来创建您的文件。它使用each_with_index方法迭代数组中的每个元素。

Using a Hash

使用哈希

When using the hash variant instead, assuming you have changed the keys in your data bag to match the syntax in your final generated file, you can loop over the hash like this:

当使用散列变体时,假设您已更改数据包中的键以匹配最终生成文件中的语法,您可以像这样循环散列:

<% @zookeeper.each_pair do |name, ipaddress| %>
<%= "#{name}=#{ipaddress}:2888:3888" %>
<% end %>

This uses the each_pair methodof the Hash to loop over each key-value pair and thus generates a line of output for each of these pairs.

这使用Hash的each_pair 方法来循环每个键值对,从而为这些对中的每一个生成一行输出。

Passing data to the template

将数据传递给模板

As a final remark, your syntax to pass data to the template in your recipe is odd. At first, you should never use names that start with an uppercase letter for variables (like your ZOOKEEPERvariable). In Ruby, these identify constants (like value constants, classes, modules, ...). Use a lowercase name instead. Ruby uses snake_case for variable names by convention.

最后要说的是,您将数据传递给配方中的模板的语法很奇怪。首先,您永远不应该使用以大写字母开头的变量名称(例如您的ZOOKEEPER变量)。在 Ruby 中,这些标识常量(如值常量、类、模块等)。请改用小写名称。按照惯例,Ruby 使用snake_case 作为变量名。

When passing the value to your template, you can then just pass the variable:

将值传递给模板时,您可以只传递变量:

db = data_bag_item("mydb", "rtb")
zookeeper = db['zookeeper']

template "/etc/zookeeper/conf/zoo.cfg" do
  path "/etc/zookeeper/conf/"
  source "zoo.cfg.erb"
  owner "root"
  group "root"
  mode "0644"
  variables :zookeeper => zookeeper
end