【问题标题】:Issue looping on block containing a set of tasks in Ansible在包含 Ansible 中的一组任务的块上发出循环
【发布时间】:2023-01-27 22:10:33
【问题描述】:

我需要检查一个名为部署.db存在。如果它不存在,我需要执行一组我正在使用块的任务。

以下是我运行剧本的方式

ansible-playbook test.yml \
  -e Layer=APP \
  -e BASEPATH="/logs" \
  -e Filenames="file1,file2,file3"

这是剧本测试.yml:

---
- name: "Play 1"
  hosts: localhost
  gather_facts: false
  tasks:
   - name: Construct 
     debug:
        msg: "Run"
   - block:
       - stat: path="{{ BASEPATH }}/deploy.db"
         register: currdb
       - file: path="{{ BASEPATH }}/deploy.db" state=touch recurse=no
         when: currdb.stat.exists == False
       - shell: "echo done>>{{ BASEPATH }}/deploy.db"
         when: currdb.stat.exists == False
     when: Layer == 'APP'
     with_items:
       - "{{ Filenames.split(',') }}" 

运行剧本时出现以下错误:

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

The error appears to be in '/app/test.yml': line 9, column 6, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

   - block:
     ^ here 

经过一番研究,我了解到 block 不支持 with_itemsloop,解决方案是包含一个任务文件。

但是,我不确定如何让它发挥作用。你能建议我需要进行哪些调整才能使我的剧本发挥作用吗?

考虑到我使用的是最新版本的 Ansible,还有其他解决方案吗?

【问题讨论】:

  • 有很多事情不清楚:您使用了无处定义的变量(图层、文件名)。此外,您的 shell-command 是一种比应有的更多的意图。请编辑您的问题
  • 抱歉,我正在使用移动设备发帖,所以格式有问题。现在我已经更新了我原来的帖子。请看一看。谢谢
  • 早在 2015 年就要求支持 Ansible 中的此功能,并进行了详细讨论,并最终于 2017 年底关闭。请参阅feature request: looping over blocks #13262

标签: ansible


【解决方案1】:

长话短说

'with_items' 不是块的有效属性

错误信息说明了一切:你不能遍历一个块。

如果你需要循环一组任务,将它们放在一个单独的文件中并使用include_tasks

实施(和一些好的做法......)

以下是基于您的示例的实现,说明了解决方案。

由于您的问题和代码不够精确,并且我指出了一些不良做法,请注意:

  • 我修复了循环代码以有效地使用你循环的 filenames(我推断它应该是 deploy.db 文件)。请注意使用 loop_control 来消除包含文件中变量名称的歧义(即 db_filename)。
  • 我通过使用 ansible 模块 copy 代替 shell 并删除了 touch 阶段,使代码尽可能地幂等。
  • 我将 var 名称转换为全部小写和下划线分隔符。
  • 为了确保复制任务在所有情况下都能正常工作,我用一个确保basepath 目录存在的单一任务替换了删除的任务。
  • 我在filenames.split(',') 之后添加了一个unique 过滤器,并在每个值上添加了一个trim 过滤器,以删除逗号分隔列表中可能的重复项和错误添加的最终空格。
  • 我使用了 not 关键字和 bool 过滤器(为了额外的安全性),而不是与布尔值 False 值进行简单比较。

这是包含的文件create_db_each.yml

---
- name: Check if file exists
  stat:
    path: "{{ basepath }}/{{ db_filename }}"
  register: currdb

- name: Create the file with "done" line if not present
  copy:
    content: "done"
    dest: "{{ basepath }}/{{ db_filename }}"
  when: not currdb.stat.exists | bool

在以下create_db.yml剧本中使用

---
- name: "Create my dbs"
  hosts: localhost
  gather_facts: false

  tasks:
    - name: Make sure the base directory exists
      file:
        path: "{{ basepath }}"
        state: directory

    - name: load each db
      include_tasks: "create_db_each.yml"
      when: layer == 'APP'
      loop: "{{ filenames.split(',') | unique | map('trim') }}"
      loop_control:
        loop_var: db_filename

这使


笔记:

  • 仅首次运行,在您身边再次运行它以见证它到处报告OK
  • 查看filenames参数值来说明uniquetrim的使用

$ ansible-playbook -e basepath=/tmp/my/base/path -e "filenames='a.bla, b.toto, c , z.txt,a.bla'"  -e layer=APP create_db.yml

PLAY [Create my dbs] ************************************************

TASK [Make sure the base directory exists] **************************
changed: [localhost]

TASK [load each db] *************************************************
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=a.bla)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=b.toto)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=c)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=z.txt)

TASK [Check if file exists] *****************************************
ok: [localhost]

TASK [Create the file with "done" line if not present] **************
changed: [localhost]

TASK [Check if file exists] *****************************************
ok: [localhost]

TASK [Create the file with "done" line if not present] **************
changed: [localhost]

TASK [Check if file exists] *****************************************
ok: [localhost]

TASK [Create the file with "done" line if not present] **************
changed: [localhost]

TASK [Check if file exists] *****************************************
ok: [localhost]

TASK [Create the file with "done" line if not present] **************
changed: [localhost]

PLAY RECAP **********************************************************
localhost: ok=13   changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ tree /tmp/my/base/path/
/tmp/my/base/path/
├── a.bla
├── b.toto
├── c
└── z.txt

$ for f in /tmp/my/base/path/*; do cat $f; echo; done
done
done
done
done

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
相关资源
最近更新 更多