在 Ansible 中,基于变量在循环中仅运行一项

Phi*_*ord 4 ansible

在我的 Ansible playbook 中,我在一台服务器上设置了多个网站。每个网站都在apps变量中设置了一些配置:

apps:
  - name: 'app1'
    git_repo: 'https://github.com/philgyford/app1.git'
  - name: 'app2'
    git_repo: 'https://github.com/philgyford/app2.git'
Run Code Online (Sandbox Code Playgroud)

然后为每个应用程序/站点循环运行某些任务:

- name: Set up git repos for apps
  git:
    repo: '{{ item.git_repo }}'
    version: 'master'
    dest: "/webapps/{{ item.name }}"
    accept_hostkey: yes
  with_items: apps
Run Code Online (Sandbox Code Playgroud)

这一切都很好。但理想情况下,我希望能够运行剧本并且只为特定应用程序运行这些任务。

一种方法是--extra-vars "app=app1"在命令行上传递。在剧本中,我为appof设置了默认值false。然后在每个与应用程序相关的任务上添加:

  when: item.name == app or app == false
Run Code Online (Sandbox Code Playgroud)

这应该可行,但必须将其添加到每个任务中似乎很费力且容易出错。有没有更优雅的方式来避免如此多的重复?

udo*_*dan 6

您可以使用筛选器列表selectattr过滤器,像这样:

apps | selectattr('name', 'match', app)
Run Code Online (Sandbox Code Playgroud)

除了您的apps定义,您还可以有一个过滤列表,默认为完整列表:

vars:
  apps:
    - name: 'app1'
      git_repo: 'https://github.com/philgyford/app1.git'
    - name: 'app2'
      git_repo: 'https://github.com/philgyford/app2.git'

  active_apps: "{{ apps if app is not defined else apps | selectattr('name', 'match', app) | list }}"
Run Code Online (Sandbox Code Playgroud)

然后在你的循环中,你会循环过去active_apps,不需要进一步的条件。

- name: Set up git repos for apps
  git:
    repo: '{{ item.git_repo }}'
    version: 'master'
    dest: "/webapps/{{ item.name }}"
    accept_hostkey: yes
  with_items: active_apps
Run Code Online (Sandbox Code Playgroud)

中使用的match过滤器selectattr实际上采用正则表达式。所以你可以提供非常详细的表达式来处理哪些应用程序。

--extra-vars "app=app1"
--extra-vars "app=app[12]"
--extra-vars "app=app.*"
--extra-vars "app=app1|app2"
...
Run Code Online (Sandbox Code Playgroud)

但要小心这一点。--extra-vars "app=app1"也会匹配app10等。

  • 非常有用的例子 - 正是我正在寻找的。为了绕过也匹配`app10`的`--extra-vars“app=app1”`,你可以使用`equalto`过滤器,例如`selectattr('name', 'equalto', app)`(虽然我不得不升级Jinja2) (2认同)