Puppet中用.map生成Hash而非数组及Hash合并的目标数组保留问题
听起来你在处理Puppet模块里的JMS配置时,遇到了两个核心问题:一是用.map返回数组导致合并操作异常,二是合并后原有target和targettype数组元素被覆盖,而不是追加。我来帮你一步步解决这个问题。
问题拆解
首先明确你的核心需求:
- 从Hiera读取
jms_subdeployment_instancesHash结构 - 基于
$array_domain_jmsserver_addresses生成新的target条目 - 将新条目追加到原有
target数组,同时对应追加相同数量的JMSServer到targettype数组 - 最终合并后的Hash要完整保留所有原有和新增的元素
修正后的代码实现
先保持你的Hiera数据(service.yaml)不变:
jms_subdeployment_instances: 'BPMJMSModuleUDDs:BPMJMSSubDM': ensure: 'present' target: - 'BPMJMSServer_auto_1' - "BPMJMSServer_auto_%{::ec2_tag_name}" targettype: - 'JMSServer' - 'JMSServer'
然后修改init.pp的代码,解决数组覆盖和类型不匹配的问题:
# 读取Hiera数据,确保默认参数配置正确 $jms_subdeployments = lookup('jms_subdeployment_instances', $default_params) # 构建用于合并的更新Hash:针对每个子部署追加target和targettype $jms_target_updates = $jms_subdeployments.reduce({}) |$accumulator, $subdep_entry| { # 解构当前子部署的名称和对应数据 $subdep_name = $subdep_entry[0] $subdep_data = $subdep_entry[1] # 从服务器地址列表生成新的target条目 $jms_short_name = $subdep_name[0, 3] # 取子部署名称前3个字符,示例中为"BPM" $new_targets = $array_domain_jmsserver_addresses.map |$server| { "${jms_short_name}JMSServer_auto_${server}" } # 合并原有数组与新数组:用concat保证是追加而非替换 $updated_target = concat($subdep_data['target'], $new_targets) # 为每个新target生成对应的targettype条目,再合并到原有数组 $updated_targettype = concat( $subdep_data['targettype'], Array.new($new_targets.size, 'JMSServer') ) # 将更新后的子部署数据加入累积Hash $accumulator + { $subdep_name => { 'target' => $updated_target, 'targettype' => $updated_targettype } } } # 使用deep_merge递归合并原始Hash和更新Hash,确保嵌套数组正确追加 $merge_subdeployment_targets = deep_merge($jms_subdeployments, $jms_target_updates)
关键改进点说明
用
reduce构建Hash而非map返回数组:.map会返回数组,而我们需要的是和原始数据结构匹配的Hash,这样deep_merge才能正常工作。reduce({})从空Hash开始,每次迭代将更新后的子部署数据加入累积器,最终得到正确的Hash结构。用
concat实现数组追加:
普通的Hash合并会直接替换键值,而concat可以把原有数组和新数组合并成一个,完美保留所有元素。对应更新
targettype数组:
用Array.new($new_targets.size, 'JMSServer')生成和新target数量一致的JMSServer数组,再和原有targettype合并,保证每个target都有对应的类型。使用
deep_merge处理嵌套结构:
普通的merge只会替换顶层键的值,而deep_merge会递归处理嵌套的Hash,确保target和targettype这些嵌套数组被正确合并,而不是被整体替换。
最终效果验证
假设$array_domain_jmsserver_addresses的值是['server1', 'server2'],最终$merge_subdeployment_targets会生成你期望的结构:
{ 'BPMJMSModuleUDDs:BPMJMSSubDM' => { 'ensure' => 'present', 'target' => [ 'BPMJMSServer_auto_1', 'BPMJMSServer_auto_your-ec2-tag-name', # Puppet会自动解析ec2_tag_name变量 'BPMJMSServer_auto_server1', 'BPMJMSServer_auto_server2' ], 'targettype' => [ 'JMSServer', 'JMSServer', 'JMSServer', 'JMSServer' ] } }
内容的提问来源于stack exchange,提问作者Dave Shaw

