如何有效地测试木偶中深层嵌套的数据值以采取行动?

How to efficiently test a deeply nested data value in puppet to take an action?

给定这样的数据结构

$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,
}

wondering if there are any better patterns in puppet for extracting data to determine if something is required or not.

关于数据结构的一些可能的改进:

  • 考虑避免这种深度嵌套
  • 考虑避免在哈希中使用可选键,尤其是在中间层
  • 考虑尽量减少散列数组的使用,因为除了遍历它们之外通常没有办法处理它们。
  • 使用具有不受控制的键空间的散列也是如此
  • 使用 Puppet 数据类型来记录和实施您选择的数据结构

至于计算模式,

  • 考虑在分析集合以计算布尔值 属性 时使用 any() 函数,因为这会让你 善意 做空电路。

  • 不要忽视 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 级别迭代的(可能的)效率改进。