使用Chef和Ansible对哈希|映射数据的多重循环进行比较

以下是使用Chef和Ansible展示按照哈希映射结构进行嵌套循环的示例。

厨师的例子

菜谱

node.default['var_test']['a']['aa']['aaa'] = 'AAA'
node.default['var_test']['a']['aa']['aab'] = 'AAB'
node.default['var_test']['a']['ab']['aba'] = 'ABA'
node.default['var_test']['b']['ba']['baa'] = 'BAA'
node.default['var_test']['c']['ca']['caa'] = 'CAA'
node.default['var_test']['c']['cb']['cba'] = 'CBA'

node['var_test'].each do |key1, val1|
  val1.each do |key2, val2|
    val2.each do |key3, val3|
      log "key1:#{key1} key2:#{key2} key3:#{key3} val:#{val3}"
    end
  end
end

可以使用.each对哈希进行简洁的多重循环描述。
此外,属性可以使用以下方式或通过传递JSON进行描述。

node.default['var_test'] = {
  'a' => { 
    'aa' => { 
      'aaa' => 'AAA',
      'aab' => 'AAB',
    },
...

执行结果

$ kitchen conv
-----> Starting Kitchen (v1.21.2)
-----> Converging <chef-loop-centos-7>...
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 7.0.2...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
-----> Chef Omnibus installation detected (install only if missing)
       Transferring files to <chef-loop-centos-7>
       Starting Chef Client, version 14.3.37
       resolving cookbooks for run list: ["chef_loop::default"]
       Synchronizing Cookbooks:
         - chef_loop (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 6 resources
       Recipe: chef_loop::default
         * log[key1:a key2:aa key3:aaa val:AAA] action write

         * log[key1:a key2:aa key3:aab val:AAB] action write

         * log[key1:a key2:ab key3:aba val:AAA] action write

         * log[key1:b key2:ba key3:baa val:BAA] action write

         * log[key1:c key2:ca key3:caa val:CAA] action write

         * log[key1:c key2:cb key3:cba val:CBA] action write


       Running handlers:
       Running handlers complete
       Chef Client finished, 6/6 resources updated in 01 seconds
       Downloading files from <chef-loop-centos-7>
       Finished converging <chef-loop-centos-7> (0m7.12s).
-----> Kitchen is finished. (0m10.56s)

在Chef中,通过在循环中逐层处理结构化数据,可以实现简洁的执行,并且保持执行顺序和数据顺序的一致。我认为这样可以获得可读性、易维护性、可移植性和抽象化等优点。

Ansible的例子

Ansible的playbook并非编程语言,而是通过使用数据结构来强行实现逻辑,因此在需要逻辑的情况下,描述非常难读。

剧本

---
- hosts: all
  vars:
    var_test:
      a:
        aa:
          aaa: AAA
          aab: AAB
        ab:
          aba: ABA
      b:
        ba:
          baa: BAA
      c:
        ca:
          caa: CAA
        cb:
          cba: CBA

  tasks:
    - name: "loop0"
      include: loop1.yml
      with_dict : "{{ vars.var_test }}"

数据具有与Chef示例相同的结构体
对于哈希|映射,可以使用with_dict进行循环,但无法指定块内容,必须使用include将循环内容分解到另一个文件中(在这种情况下是loop1.yml)。
因此,可读性和可维护性较低。

参考:想要在Ansible块单位循环,但由于无法实现而需要变通方法。

---
- name: loop1
  include: loop2.yml
  with_dict: "{{ item.value }}"
  loop_control:
    loop_var: item1

为了进一步循环,需要进一步分割文件。(在这里使用loop2.yml)
需要注意的是,如果简单地创建第二个循环,会导致指定内容为”item”的关键字重复,因此使用了别名”item1″。


---
- name: loop2
  debug: msg="key1:{{ item.key }} key2:{{ item1.key }} key3:{{ item2.key }} val:{{ item2.value }}"
  with_dict: "{{ item1.value }}"
  loop_control:
    loop_var: item2

在循环结束时,执行处理部分的代码。
为避免关键词重复,使用了别名item2。

执行结果

$ kitchen conv
-----> Starting Kitchen (v1.21.2)
-----> Converging <ansible-loop-centos-7>...
       Preparing files for transfer
       *************** AnsiblePush install_command ***************
       Ansible push config validated
       Transferring files to <ansible-loop-centos-7>
       *************** AnsiblePush run ***************

PLAY [all] ******************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [ansible-loop-centos-7]

TASK [loop0] ****************************************************************************************
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop1.yml for ansible-loop-centos-7
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop1.yml for ansible-loop-centos-7
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop1.yml for ansible-loop-centos-7

TASK [loop1] ****************************************************************************************
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop2.yml for ansible-loop-centos-7
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop2.yml for ansible-loop-centos-7

TASK [loop2] ****************************************************************************************
ok: [ansible-loop-centos-7] => (item={'value': u'AAA', 'key': u'aaa'}) => {
    "msg": "key1:a key2:aa key3:aaa val:AAA"
}
ok: [ansible-loop-centos-7] => (item={'value': u'AAB', 'key': u'aab'}) => {
    "msg": "key1:a key2:aa key3:aab val:AAB"
}

TASK [loop2] ****************************************************************************************
ok: [ansible-loop-centos-7] => (item={'value': u'ABA', 'key': u'aba'}) => {
    "msg": "key1:a key2:ab key3:aba val:ABA"
}

TASK [loop1] ****************************************************************************************
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop2.yml for ansible-loop-centos-7
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop2.yml for ansible-loop-centos-7

TASK [loop2] ****************************************************************************************
ok: [ansible-loop-centos-7] => (item={'value': u'CBA', 'key': u'cba'}) => {
    "msg": "key1:c key2:cb key3:cba val:CBA"
}

TASK [loop2] ****************************************************************************************
ok: [ansible-loop-centos-7] => (item={'value': u'CAA', 'key': u'caa'}) => {
    "msg": "key1:c key2:ca key3:caa val:CAA"
}

TASK [loop1] ****************************************************************************************
included: /Users/aa220269/repo/repo-test/cookbooks/ansible_loop/recipes/loop2.yml for ansible-loop-centos-7

TASK [loop2] ****************************************************************************************
ok: [ansible-loop-centos-7] => (item={'value': u'BAA', 'key': u'baa'}) => {
    "msg": "key1:b key2:ba key3:baa val:BAA"
}

PLAY RECAP ******************************************************************************************
ansible-loop-centos-7      : ok=14   changed=0    unreachable=0    failed=0   

       *************** AnsiblePush end run *******************
       Downloading files from <ansible-loop-centos-7>
       Finished converging <ansible-loop-centos-7> (0m5.49s).
-----> Kitchen is finished. (0m8.37s)

日志很难读且缺乏可维护性。
执行顺序没有得到保障。

广告
将在 10 秒后关闭
bannerAds