【问题标题】:using .map (or another stdlib feature) to create a hash not array使用 .map(或其他 stdlib 功能)创建散列而不是数组
【发布时间】:2019-07-19 14:32:53
【问题描述】:

我正在尝试以云中的 JMS 服务器为目标,puppet 模块 init.pp 需要将密钥添加到哈希中。

我正在读取一个 hiera 块,并且必须提取其中的一部分以形成一个新的哈希。 .each 不返回任何值,所以我使用的是 .map。 我得到的值正是我想要的,但是当我尝试 deep_merge 时,我发现 .map 输出为一个数组。

service.yaml

jms_subdeployment_instances:
   'BPMJMSModuleUDDs:BPMJMSSubDM':
      ensure:     'present'
      target:
       - 'BPMJMSServer_auto_1'
       - "BPMJMSServer_auto_%{::ec2_tag_name}"
      targettype:
        - 'JMSServer'
        - 'JMSServer'      

init.pp

  $jms_subdeployments = lookup('jms_subdeployment_instances', $default_params)
  $jms_target_args = $jms_subdeployments.map |$subdep, $value| {
    $jms_short_name = $subdep[0, 3]
    $jms_subdeployment_inst = $array_domain_jmsserver_addresses.map |$index, $server| {
      "${jms_short_name}JMSServer_auto_${server}"

      if defined('$jms_subdeployment_inst') {
        $jmsTargetArg = {
          "${subdep}" => {
            'target' => $jms_subdeployment_inst
          }
        }
      }
    }

  $merge_subdeployment_targets = merge($jms_subdeployments, $jms_target_args)



```Output
New JMS targets are : [{BPMJMSModuleUDDs:BPMJMSSubDM => {target => [BPMJMSServer_auto_server101, BPMJMSServer_auto_server102]}}]

封闭的 [ ] 给我带来了麻烦。据我所知,在 puppet 中 .to_h 也不起作用

谢谢

22/07/2019 更新:

感谢您的回复,我不得不稍微调整一下,因为 puppet 失败并显示“服务器错误:评估错误:评估方法调用时出错,'values' 参数 'hsh' 需要一个哈希值,得到元组”

  $array_domain_jmsserver_addresses = 
  any2array(hiera('pdb_domain_msserver_addresses'))
  $array_domain_jmsserver_addresses.sort()
  $jms_subdeployments = lookup('jms_subdeployment_instances', $default_params)
  $hash_domain_jmsserver_addresses = Hash($array_domain_jmsserver_addresses)

  if $hash_domain_jmsserver_addresses.length > 0 {
      $jms_target_arg_tuples = $jms_subdeployments.keys.map |$subdep| {
      $jms_short_name = $subdep[0, 3]
      $jms_subdeployment_inst = regsubst(
          $hash_domain_jmsserver_addresses.values, /^/, "${jms_short_name}JMSServer_auto_")

  # the (key, value) tuple to which this element maps
  [ $subdep, { 'target' => $jms_subdeployment_inst } ]
}

$jms_target_args = Hash($jms_target_arg_tuples)
} else {
$jms_target_args = {}
}

notify{"Normal array is : ${jms_subdeployments}": }
notify{"Second array is : ${jms_target_args}": }  

$merge_subdeployment_targets = deep_merge($jms_subdeployments, $jms_target_args)
notify{"Merged array is : ${merge_subdeployment_targets}": }

正常是:{BPMJMSModuleUDDs:BPMJMSSubDM => {ensure => present, target => [BPMJMSServer_auto_1, BPMJMSServer_auto_server1], targettype => [JMSServer, JMSServer]},

第二个是:{BPMJMSModuleUDDs:BPMJMSSubDM => {target => [BPMJMSServer_auto_server2]}

合并为:{BPMJMSModuleUDDs:BPMJMSSubDM => {ensure => present, target => [BPMJMSServer_auto_server2], targettype => [JMSServer, JMSServer]}

想要的输出:

{BPMJMSModuleUDDs:BPMJMSSubDM => {确保 => 存在,目标 => [BPMJMSServer_auto_1, BPMJMSServer_auto_server1, BPMJMSServer_auto_server2], targettype => [JMSServer, JMSServer, JMSServer]}

【问题讨论】:

  • 您的代码有不平衡的括号。我认为我已经明白你的意思了,但如果是这样,那么你的代码也有不一致的缩进。
  • 如果我的答案中的(不同的)修订版不能解决问题,那么如何通过用文字替换所有 lookup() 调用来更接近 minimal reproducible example。我在回答中提供的代码是对您的原始代码的改编,但如果它首先不太适合实际数据,那么我们没有足够的信息来让您到达您想要的位置。

标签: arrays hash puppet hiera


【解决方案1】:

当我尝试 deep_merge 时,我发现 .map 输出为数组。

是的,这是its documented behaviormap() 应被视为集合的元素上的函数,而不是整个集合上的函数,并且结果始终以数组的形式提供。

查看converting values to hashes 的替代方案可能会很有用。这个特别吸引人:

  • 匹配 Array[Tuple[Any,Any], 1]Array 被转换为每个元组描述一个键/值条目的哈希

为了利用这一点,将每个条目映射到一个(键,值)元组,并将生成的元组数组转换为哈希。将您的尝试转换为该方法可能如下所示:

if $array_domain_jmsserver_addresses.length > 0 {
  $jms_target_arg_tuples = $jms_subdeployments.keys.map |$subdep| {
    $jms_short_name = $subdep[0, 3]
    $jms_subdeployment_inst = regsubst(
        $array_domain_jmsserver_addresses.sort, /^/, "${jms_short_name}JMSServer_auto_")

    # the (key, value) tuple to which this element maps
    [ $subdep, { 'target' => $jms_subdeployment_inst } ]
  }

  $jms_target_args = Hash($jms_target_arg_tuples)
} else {
  $jms_target_args = {}
}

$merge_subdeployment_targets = merge($jms_subdeployments, $jms_target_args)

请注意,由于您不使用$jms_subdeployments 的值,因此我冒昧地通过对其应用keys() 函数来简化您的代码。我还使用regsubst() 而不是map()$array_domain_jmsserver_addresses 的元素中形成目标名称,我个人认为在这种情况下更易读,尤其是因为您没有使用索引。

我还推断出我认为您的 if defined() 测试要完成什么,并将其替换为 $array_domain_jmsserver_addresses 数组长度的最外层测试。也可以用更实用的形式编写它,通过构建散列而不考虑是否有任何目标,然后filter()ing 它,但这似乎很浪费,因为看起来所有条目都将具有(相同)目标,否则没有目标。

【讨论】:

  • 感谢您快速详细的回复,我已经更新了原始问题。有趣的是,合并还没有完全奏效
  • @DaveShaw,我已经适当地调整了这个答案中的代码 $array_domain_jmsserver_addresses 是一个数组而不是一个哈希。
猜你喜欢
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多