【问题标题】:Nest with_filetree and loop嵌套 with_filetree 和循环
【发布时间】:2020-07-09 00:14:59
【问题描述】:

如何嵌套 with_filetree 和循环?

这是我使用块的尝试:

- name: Deploy
  hosts: all
  connection: ssh
  become: true

  vars:
    instances:
      abcd:
        admin_port: 12345
  
  tasks:
    - name: Template cfg
      vars:
        file_path: "{{ item.path }}"
      block:
        - name: Templating config files
          vars:
            instance: "{{ item.value }}"
          template:
            src: "config-templates/{{ file_path }}"
            dest: "{{ install_dir }}/{{ instance.name }}/"
          loop: "{{ instances | dict2items }}"
      with_filetree: "config-templates"
      when: item.state == 'file'

但是 ansible 抱怨:

ERROR! 'with_filetree' is not a valid attribute for a Block

我一定遗漏了一些明显的东西,但我不知道该怎么做。使用 with_nested/with_cartesian 似乎不起作用。

请帮忙。

【问题讨论】:

  • 你不能遍历一个块。实际上,您实际上不能在包含文件的 ansible appart 循环中真正嵌套循环。这可能是这里的解决方案。警告:您必须使用loop_control: {loop_var: someothervar} 来区分内部和外部循环变量,否则它们将在同一个item 上发生冲突。
  • @Zeitounator 感谢您向我展示了一种方法。不确定您提到的是否是include_tasks,但它的工作方式与您描述的一样。
  • 我就是这个意思。同时,经过短暂的睡眠后,我能够通过单个任务测试另一个(我相信......)工作解决方案。请参阅下面的答案。

标签: ansible


【解决方案1】:

当包含任务中有多个循环时,使用包含嵌套循环是唯一可行的解​​决方案。

同时在大多数情况下,包括您的情况,您可以将工作减少到一个循环。基本思想:不是嵌套循环,而是创建一个包含所有要循环的元素的列表。在这种情况下,product filter 应该可以完成这项工作。

另一个“诀窍”(因为文档中没有 filetree... 的真实示例)是记住 with_<some_lookup> 循环通常可以转换为 loop: {{ lookup|query('some_lookup', args....) }}

总而言之,这是一个(未完全测试)应该满足您的要求的示例:

- name: Templating from filetree and instances
  vars:
    file: "{{ item.0 }}"
    instance: "{{ item.1.value }}"
  template:
    src: "config-templates/{{ file.path }}"
    dest: "{{ install_dir }}/{{ instance.name }}/"
  loop: "{{ lookup('filetree', 'templates/config') | product(instances | dict2items) | list }}"
  when: file.state == 'file'

编辑:不要试图推向“我的!!!”解决方案 :),但如果您没有太多任务,可以将所有内容保存在同一个文件中。

Edit2:您实际上甚至不需要任务,尤其是当您的游戏针对多个主机时。更新了一个完整的伪剧本示例。

- name: Deploy
  hosts: all
  connection: ssh
  become: true

  vars:
    my_files: "{{ lookup('filetree', 'templates/config') | selectattr('state', 'eq', 'file') | list }}"
    action1_list: ['some', 'list']
    action2_list: ['other', 'list']
    
  tasks:
    - name: action 1
      debug:
        msg: action1
      vars:
        file: item.0
        action1_item: item.1
      loop: "{{ my_files | product(action1_list) | list }}"

    - name: action 2
      debug:
        msg: action2
      vars:
        file: item.0
        action2_item: item.1
      loop: "{{ my_files | product(action2_list) | list }}"

【讨论】:

  • 你太棒了!不幸的是,实际上我有多个任务要在实例的外部循环中运行,一些带有文件树,一些只是简单的非循环任务。所以我想我坚持使用 include_tasks 和一个额外的文件。但是,既然这回答了我的问题,我会接受,如果没有出现更简单和/或适用于多个任务的内容。
  • 查看我的编辑以获取可能的解决方案。选择是你的;)
  • 你应该得到另一个支持 - 我希望我能。但这看起来最终会成为公认的答案:) 我稍后会尝试将其应用到我的场景中。
  • 让解决方案更加性感 ;)
【解决方案2】:

感谢 Zeitounator 的评论,我能够创建一个解决方案。然而,它有一个缺点,就是内部循环任务需要放在一个单独的文件中。

  tasks:
    - name: Template cfg
      include_tasks: inner-template-tasks.yaml
      with_filetree: "templates/config"
      when: item.state == 'file'

inner-template-tasks.yaml 看起来像这样:

- name: Templating {{ item.path }}
  vars:
    instance: "{{ loop_item.value }}"
  template:
    src: "config-templates/{{ item.path }}"
    dest: "{{ install_dir }}/{{ instance.name }}/"
  loop: "{{ instances | dict2items }}"
  loop_control:
    loop_var: loop_item

我只是想知道为什么 ansible 强迫我们为此使用单独的文件...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2013-09-22
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多