puppet - 自定义函数中'each'的意外结果

时间:2016-01-23 11:43:09

标签: ruby function puppet

我有一个简单的函数,它使用JSON和'做某事'。主要部分工作正常但该功能不仅返回我想要的,而且还返回 .each 循环的结果!

代码:

  module Puppet::Parser::Functions
    newfunction(:mlh, :type => :rvalue) do |args|

    lvm_default_hash    = args[0]
    lvm_additional_hash = args[1]

    if lvm_additional_hash.keys.length == 1
      if lvm_additional_hash.keys.include? 'logical_volumes'
        # do stuff - we have only 'logical_volumes'
        lvm_default_hash.keys.each do |key|

          pv_array       = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
          lv_hash        = lvm_default_hash[key]['logical_volumes']
          new_lv_hash    = lvm_additional_hash['logical_volumes']
          merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]

          # this is what I want to return to init.pp
          puts Hash[key => pv_array.merge(merged_lv_hash)]

        end
      end
    end
  end
end

init.pp 中的变量是:

$default_volume_groups = {
'sys' => {
  'physical_volumes' => [
    '/dev/sda2',
  ],
  'logical_volumes' => {
    'root'   => {'size' => '4G'},
    'swap'   => {'size' => '256M'},
    'var'    => {'size' => '8G'},
    'docker' => {'size' => '16G'},
  },
},

}

和hieradata的第二个参数:

modified_volume_groups:
logical_volumes:
  cloud_log:
    size: '16G'

init.pp 中我有类似的东西来测试它:

notice(mlh($default_volume_groups, $modified_volume_groups))

给了我一个结果:

syslogical_volumesvarsize8Gdockersize16Gcloud_logsize16Gswapsize256Mrootsize4Gphysical_volumes/dev/sda2
Notice: Scope(Class[Ops_lvm]): sys

通知之前的“长”部分是来自 puts 的正确结果,但注意:Scope():sys 就是这样我不知道想要! 我知道这是每个循环对 default_volumes_groups 的结果:

lvm_default_hash.keys.each do |key|
  # some stuff
end

如何阻止这种不必要的结果?它打破了我的木偶逻辑,因为我的 init.pp 看到了这个 sys ,而不是我想要的。

有人知道如何处理这样的问题吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

我找到了如何处理这个问题,但也许有人可以用这种方式解释我为什么这样做:)

这不起作用(短版):

module Puppet::Parser::Functions
  newfunction(:mlh, :type => :rvalue) do |args|

    lvm_default_hash    = args[0]
    lvm_additional_hash = args[1]

    if lvm_additional_hash.keys.length == 1
      if lvm_additional_hash.keys.include? 'logical_volumes'
        lvm_default_hash.keys.each do |key|

          pv_array       = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
          lv_hash        = lvm_default_hash[key]['logical_volumes']
          new_lv_hash    = lvm_additional_hash['logical_volumes']
          merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]

          puts Hash[key => pv_array.merge(merged_lv_hash)]

        end
      end
    end
  end
end

但这有效:

module Puppet::Parser::Functions
  newfunction(:mlh, :type => :rvalue) do |args|

    lvm_default_hash    = args[0]
    lvm_additional_hash = args[1]

  # empty Hash
    hash_to_return = {}

    if lvm_additional_hash.keys.length == 1
      if lvm_additional_hash.keys.include? 'logical_volumes'
        lvm_default_hash.keys.each do |key|

          pv_array       = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
          lv_hash        = lvm_default_hash[key]['logical_volumes']
          new_lv_hash    = lvm_additional_hash['logical_volumes']
          merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]

        # assigned value in the 'each' loop we want to return to puppet
          hash_to_return = Hash[key => pv_array.merge(merged_lv_hash)]

        end

      # returned Hash - instead of previous 'puts'
        return hash_to_return

      end
    end
  end
end

现在我有我需要的东西!

Notice: Scope(Class[Ops_lvm]): sysphysical_volumes/de

答案 1 :(得分:1)

你已经得到了 - 第一个不起作用,因为在Ruby中,块或函数的返回值是最后一个被评估的语句。对于不起作用的情况,最后评估的语句是.each。事实证明,each评估它可以循环的可枚举。

一个简单的例子:

def foo
  [1, 2, 3].each do |n|
    puts n
  end
end

如果我要运行它,函数的返回值将是数组:

> foo
1
2
3
=> [1, 2, 3]

所以你的工作是什么,因为评估的最后一件事是return hash_to_return。你甚至可以去hash_to_return它就可以了。

如果您想摆脱return并稍微清理一下(如果您使用的是Ruby 1.9或更高版本),您可以将each行替换为:

lvm_default_hash.keys.each_with_object({}) do |key, hash_to_return|

这是因为each_with_object计算到“对象”(在这种情况下是传递给方法的空哈希,在块参数中称为hash_to_return)。如果您这样做,可以删除return以及初始化hash_to_return = {}

希望这有帮助!

答案 2 :(得分:0)

您的自定义函数具有右值类型,这意味着它需要返回值。如果您默认情况下未指定return <something>,则您的最后一个陈述将隐含地返回 在上面的示例中,第一个无法正常工作,在每个块中都有最后一条语句:

puts Hash[key => pv_array.merge(merged_lv_hash)]

你的第二个例子是正确的,因为你在每个块中为hash_to_return设置了值,然后&#34;返回&#34;它在每个街区之外。不确定这是否是您想要的行为,因为上次分配的哈希值(在每个块内的最后一个循环中)将是从此函数返回的行为。