Ansible中如何直接更新字典内列表项?避免重复创建新字典
优化Ansible字典列表项的更新方式
问题描述
我目前通过创建新字典覆盖原字典的方式更新字典列表中的项,但需要更新多个这类字典,不想每次都创建新字典。另外,命令输出的列表不固定,要为每个项的filelist添加不同内容,求更优实现方式。
原实现代码
tmp.yml
- name: Loop over specific keys in a dictionary hosts: localhost gather_facts: true vars: java_keystore_cred_list: - { application_name: keystore_certs, certs_dir_path: '/etc/keystore', command: "ls -1 ./*.yml", filelist: [] } - { application_name: app_certs, certs_dir_path: '/etc/keystore/app_certs', command: "ls -1 ./*.yml", filelist: [] } new_cred_list: [] tasks: - debug: var: java_keystore_cred_list - name: Update credential include_tasks: tmp2.yml loop: "{{ java_keystore_cred_list }}" - name: Update java_keystore_cred_list set_fact: java_keystore_cred_list: "{{ new_cred_list }}" - debug: var: java_keystore_cred_list
tmp2.yml
- name: Get filelist shell: "{{ item.command }}" register: result - name: Update filelist in item set_fact: tmp_item: "{{ item | combine({'filelist': result.stdout_lines | from_yaml}) }}" - name: Update new_cred_list set_fact: new_cred_list: "{{ (new_cred_list | default([])) + [ tmp_item ] }}"
优化方案
可以直接利用Ansible的loop注册结果,结合combine过滤器和Jinja2列表推导式生成更新后的列表,无需维护临时列表,代码更简洁高效。
优化后的tmp.yml
- name: 循环更新字典列表中的指定项 hosts: localhost gather_facts: true vars: java_keystore_cred_list: - { application_name: keystore_certs, certs_dir_path: '/etc/keystore', command: "ls -1 ./*.yml", filelist: [] } - { application_name: app_certs, certs_dir_path: '/etc/keystore/app_certs', command: "ls -1 ./*.yml", filelist: [] } tasks: - debug: var: java_keystore_cred_list - name: 获取每个项的文件列表 shell: "{{ item.command }}" register: file_results loop: "{{ java_keystore_cred_list }}" - name: 生成更新后的字典列表 set_fact: java_keystore_cred_list: >- {% set updated_list = [] %} {% for idx, item in enumerate(java_keystore_cred_list) %} {% set updated_item = item | combine({'filelist': file_results.results[idx].stdout_lines}) %} {% do updated_list.append(updated_item) %} {% endfor %} {{ updated_list }} - debug: var: java_keystore_cred_list
优化说明
- 移除了临时列表
new_cred_list和外部任务文件,逻辑更集中,减少冗余代码 - 通过
register一次性捕获所有循环的执行结果,避免多次调用set_fact累加数据 - 若使用Ansible 2.10+版本,也可以用更简洁的
map写法替代列表推导:- name: 生成更新后的字典列表 set_fact: java_keystore_cred_list: "{{ java_keystore_cred_list | zip(file_results.results) | map(lambda x: x[0] | combine({'filelist': x[1].stdout_lines})) | list }}"
优化后执行输出
ansible-playbook tmp.yml ✔ ansible2_13 🐍 [警告]: 提供的主机列表为空,仅localhost可用。注意隐式的localhost不匹配'all' PLAY [循环更新字典列表中的指定项] ********************************************************************************************************************************* TASK [debug] ******************************************************************************************************************************************************************* ok: [localhost] => java_keystore_cred_list: - application_name: keystore_certs certs_dir_path: /etc/keystore command: ls -1 ./*.yml filelist: [] - application_name: app_certs certs_dir_path: /etc/keystore/app_certs command: ls -1 ./*.yml filelist: [] TASK [获取每个项的文件列表] ************************************************************************************************************************************************************ changed: [localhost] => (item={'application_name': 'keystore_certs', 'certs_dir_path': '/etc/keystore', 'command': 'ls -1 ./*.yml', 'filelist': []}) changed: [localhost] => (item={'application_name': 'app_certs', 'certs_dir_path': '/etc/keystore/app_certs', 'command': 'ls -1 ./*.yml', 'filelist': []}) TASK [生成更新后的字典列表] ****************************************************************************************************************************************** ok: [localhost] TASK [debug] ******************************************************************************************************************************************************************* ok: [localhost] => java_keystore_cred_list: - application_name: keystore_certs certs_dir_path: /etc/keystore command: ls -1 ./*.yml filelist: - ./tmp.yml - ./tmp2.yml - application_name: app_certs certs_dir_path: /etc/keystore/app_certs command: ls -1 ./*.yml filelist: - ./tmp.yml - ./tmp2.yml PLAY RECAP ********************************************************************************************************************************************************************* localhost : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
内容的提问来源于stack exchange,提问作者Umesh
相关产品推荐
相关产品推荐

