Hash 如何在puppet中有效地测试深度嵌套的数据值以执行操作?

Hash 如何在puppet中有效地测试深度嵌套的数据值以执行操作?,hash,puppet,reduce,Hash,Puppet,Reduce,给定一个数据结构,如 $local_users => { "user" => { "ssh" => { "config_entries" => [ { "host" => "dummyhost", "lines" => [ "ProxyCommand /usr/bin/corkscrew proxy.example.net 8080 %h %p" ]

给定一个数据结构,如

$local_users => {
  "user" => {
    "ssh" => {
      "config_entries" => [
        { "host" => "dummyhost",
          "lines" => [
            "ProxyCommand /usr/bin/corkscrew proxy.example.net 8080 %h %p"
          ]
        }
      ]
    }
  }
}
我已经整理了几个reduce调用,但不确定是否有更有效的方法来确定是否有元素匹配某些条件。我认为,如果找到匹配项,这至少会开始跳过后续项,但执行3个reduce调用来提取嵌套得如此之深的内容似乎有点笨拙,我想知道puppet中是否有更好的模式来提取数据以确定是否需要某些内容

$require_corkscrew = $local_users.reduce(false) |$memo, $user| {
  $memo or dig44($user[1], ['ssh', 'config_entries'], []).reduce |$memo, $entry| {
    $memo or $entry['lines'].reduce |$memo, $line| {
      $memo or $line.match(/ProxyCommand.*corkscrew/)
    }
  }
}

if $require_corkscrew {
  $corkscrew_ensure = 'present'
} else {
  $corkscrew_ensure = 'absent'
}

package {'corkscrew':
  ensure => $corkscrew_ensure,
}
想知道puppet中是否有更好的模式用于提取数据以确定是否需要某些东西

$require_corkscrew = $local_users.reduce(false) |$memo, $user| {
  $memo or dig44($user[1], ['ssh', 'config_entries'], []).reduce |$memo, $entry| {
    $memo or $entry['lines'].reduce |$memo, $line| {
      $memo or $line.match(/ProxyCommand.*corkscrew/)
    }
  }
}

if $require_corkscrew {
  $corkscrew_ensure = 'present'
} else {
  $corkscrew_ensure = 'absent'
}

package {'corkscrew':
  ensure => $corkscrew_ensure,
}
在数据结构方面有一些可能的改进:

  • 考虑避免这种深嵌套
  • 考虑避免散列中的可选键,尤其是在中间层
  • 考虑最小化散列数组的使用,因为通常只有通过迭代来处理它们
  • 对于具有非受控密钥空间的散列,同上
  • 请使用Puppet数据类型来记录和强制执行您选择的数据结构
至于计算模式

  • 在分析集合以计算布尔属性时,请考虑使用该函数,因为这会使您真正短路

  • 不要忽略分析哈希的
    keys()
    values()
    函数,因为它们至少可以在处理复杂数据结构时减少代码的认知负载

  • 考虑使用直接操作集合的函数和函数变体,而不是迭代集合和在元素上使用标量函数。例如,
    match()

这是一种我比您的原始代码更喜欢的方法。它使用嵌套的
any()
计算和
match
函数的数组版本,而不是嵌套的缩减。它依赖于
undef
是错误的这一事实,并使用
dig()
then()
来处理可选的哈希键。总的来说,我认为这更清晰,重量更轻,但要实现用于分析复杂数据的简单代码,您只能做这么多

$require_corkscrew = $local_users.values.any |$user| {
  $user.dig('ssh', 'config_entries').then |$entries| {
    $entries.any |$entry| {
      $entry.dig('lines').then |$lines| {
        ! empty($lines.match(/ProxyCommand.*corkscrew/))
      }
    }
  }
}

可以用另一个围绕标量
match()
any()
替换数组方式的
match()
,但是,尽管它有可能在元素方式的意义上稍早短路,但必须对其进行权衡(可能)通过减少函数调用的数量,以及在函数内部而不是在DSL级别进行迭代来提高效率。

我发布了一个关于使用
dig
解决此问题的答案,但我现在意识到,这对1没有帮助。
n
config\u条目中有一个
n个
散列数
数组和2个
match
只能在
String
类型上调用,而不能在
undef
上调用。这非常方便,当时不知道
then
函数,这有很大的不同,当然,我们应该更加了解
any
函数,但没有完全单击如何应用它。问题是,即使内置事实也是嵌套的,因此您无法真正避免嵌套
.dig
使处理它们变得合理,但在处理复杂结构时,木偶并没有那么好