Ansible:在循环中合并stdout_results dict项的元素

问题描述 投票:0回答:2

我尝试维护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]) 

如果我使用techrafs建议没有when子句

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'"}

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

ansible jinja2
2个回答
0
投票

你的模板:

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

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

当你想迭代所有stdout_lines的元素时,你需要展平你的结果:

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

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 }}"
© www.soinside.com 2019 - 2024. All rights reserved.