Ansible:循环中合并stdout_results字典项的元素

时间:2018-09-12 09:58:35

标签: ansible jinja2

我尝试维护nginx配置文件摘要的模板。我想将这些代码片段应用于不同类型的Web服务器,其中每个服务器仅需要这些代码片段的一个子集。 我的方法(也许有更好的方法)是为每个host_group创建子目录(例如代理节点)并链接所需的文件,因此我只需要将模板维护在一个位置即可。 我的模板文件夹如下所示:

    nginx.conf
    proxy-nodes
    ├── conf.d
    └── snippets
        ├── cors.conf -> ../../snippets/cors.conf
        ├── proxy_backend.conf -> ../../snippets/proxy_backend.conf
        ├── proxy_conditions.conf -> ../../snippets/proxy_conditions.conf
        ├── proxy_location_assets.conf -> ../../snippets/proxy_location_assets.conf
        ├── proxy_static_params.conf -> ../../snippets/proxy_static_params.conf
        └── ssl.conf -> ../../snippets/ssl.conf
    snippets
    ├── backend.conf
    ├── ban.conf
    ├── cors.conf
    ├── proxy_backend.conf
    ├── proxy_conditions.conf
    ├── proxy_location_assets.conf
    ├── proxy_static_params.conf
    └── ssl.conf

然后,我尝试提取需要模板到主机的文件列表:

- name: create dict of group dirs with snippets files                                               
  shell: ls roles/nginx/templates/{{ item|quote }}/snippets/* | cut -d'/' -f4-
  register: nginx_group_dirs 
  delegate_to: localhost
  with_lines: for i in $(ls -d roles/nginx/templates/*/); do echo $i | cut -f4 -d'/'; done
  when: item in group_names

这使我在nginx_group_dirs.results.item.stdout_lines中包含文件的多个项目:

"nginx_group_dirs": {
    "changed": true, 
    "msg": "All items completed", 
    "results": [
 ...
            },
            "item": "proxy-nodes", 
            "rc": 0, 
            "start": "2018-09-12 10:45:14.652846", 
            "stderr": "", 
            "stderr_lines": [], 
            "stdout": "proxy-nodes/snippets/backend.conf\nproxy-nodes/snippets/ban.conf\nproxy-nodes/snippets/cors.conf\nproxy-nodes/snippets/proxy_backend.conf\nproxy-nodes/snippets/proxy_conditions.conf\nproxy-nodes/snippets/proxy_location_assets.conf\nproxy-nodes/snippets/proxy_static_params.conf\nproxy-nodes/snippets/ssl.conf", 
            "stdout_lines": [
                "proxy-nodes/snippets/cors.conf", 
                "proxy-nodes/snippets/proxy_backend.conf", 
                "proxy-nodes/snippets/proxy_conditions.conf", 
                "proxy-nodes/snippets/proxy_location_assets.conf", 
                "proxy-nodes/snippets/proxy_static_params.conf", 
                "proxy-nodes/snippets/ssl.conf"
            ]
        }, 
        {
            "_ansible_ignore_errors": null, 
            "_ansible_item_label": "snippets", 
            "_ansible_item_result": true, 
            "_ansible_no_log": false, 
            "changed": false, 
            "item": "snippets", 
            "skip_reason": "Conditional result was False", 
            "skipped": true
        }, 

后来我意识到,虽然列出仅用于匹配group_names的目录结构会导致某些项目没有stdout_lines。 我现在的问题是找到合适的循环和/或过滤器语法来模板化多个项目的所有相关stdout_lines文件。

- name: template snippets for all applicable groups
  template: 
    src: "{{ item }}"
    dest: "/etc/nginx/snippets/{{ item | basename }}"
    backup: yes
    with_items: "{{ nginx_group_dirs.results | map(attribute='stdout_lines') | list }}"
    when: item.stdout_lines is defined

我添加了when:子句,该子句为我提供了此输出(这里还有更多内容,以防我不想扩展帖子:

TASK [nginx : template snippets for all applicable groups] ********************************************
skipping: [eu-proxy1] => (item=[Undefined, Undefined, Undefined, [u'eu-proxy-nodes/sites-available/default'], [u'proxy-nodes/snippets/cors.conf', u'proxy-nodes/snippets/proxy_backend.conf', u'proxy-nodes/snippets/proxy_conditions.conf', u'proxy-nodes/snippets/proxy_location_assets.conf', u'proxy-nodes/snippets/proxy_static_params.conf', u'proxy-nodes/snippets/ssl.conf'], Undefined, Undefined]) 

如果我使用无when子句的techrafs建议

with_items: "{{ nginx_group_dirs.results | map(attribute='stdout_lines') | flattened }}"

我得到了(因为某些项目没有'stdout_lines'吗?):

fatal: [eu-proxy1]: FAILED! => {"msg": "'dict object' has no attribute 'stdout_lines'"}

所以我想我还需要以某种方式摆脱未定义的项。有任何想法吗 ?

2 个答案:

答案 0 :(得分:0)

您的模板:

{{ nginx_group_dirs.results | map(attribute='stdout_lines') | list }}

产生一个列表列表(stdout_lines)。

当您要遍历所有stdout_lines的元素时,需要将结果展平:

{{ nginx_group_dirs.results | map(attribute='stdout_lines') | flatten }}

答案 1 :(得分:0)

我找到了一种使模板运行的方法,但对我来说有点奇怪:

- name: create dict of group dirs with subdirs and files
  shell: ls -d1 roles/nginx/templates/{{ item|quote }}/*/* | cut -d'/' -f4- 
  register: nginx_group_dirs
  delegate_to: localhost
  with_lines: for i in $(ls -d roles/nginx/templates/*/); do echo $i | cut -f4 -d'/'; done
  when: item in group_names

- debug: msg="{{ item.stdout_lines | default([]) }}"
  register: file_list
  loop: "{{ nginx_group_dirs.results }}"

- name: template snippets for all applicable groups
  template: 
    src: "{{ item }}"
    dest: "/etc/nginx/{{ item | regex_replace('^(\\w(-?))+\\/', '') }}"
    backup: yes
  loop: "{{ file_list.results | map(attribute='msg') | flatten }}"