Ansible 2 conditionals using with_items in loop

狂风中的少年 提交于 2019-12-11 04:07:32

问题


I'm trying to run a few Ansible commands depending on the outcome of a conditional check in my tasks based on the presence of a boolean and am tying myself up in knots trying to get it to work.

The desired outcome is as follows, and should be run for each item in the hosts array:

  • Check if the lynchburg variable is true or false
  • If the lynchburg variable is true:
    • Setup the folder structure if it doesn't already exist
    • Create gulpfile.js from the included template file if it doesn't already exist
  • If the lynchburg variable is false:
    • Don't setup the folder structure
    • Don't create gulpfile.js
  • Regardless of whether the lynchburg is true or false, skip all tasks on subsequent reprovisions, as the folder structure and gulpfile.js will either be there or not (although this should be taken care of by the logic in the conditionals)

From the code included below, I'm seeing the following results:

  • When lynchburg is true, the provision runs through as expected the first time around and any subsequent reprovisions also work as expected.
  • When lynchburg is false, the inc folder structure is created, however gulpfile.js isn't.

The main loop the task should run through is the following:

vhosts:
  - site_name: sample
    lynchburg: true

and the tasks are as follows:

# Create variable to check whether Lynchburg has already been installed
- name: Check if Lynchburg assets folders have been previously created
  stat:
    path: /var/www/{{ item.site_name }}/inc
  with_items: "{{ vhosts }}"
  when: item.lynchburg == true
  register: lynchburg_assets

- name: Check if Lynchburg gulpfile.js has been previously created
  stat:
    path: /var/www/{{ item.site_name }}/gulpfile.js
  with_items: "{{ vhosts }}"
  when: item.lynchburg == true
  register: lynchburg_gulpfile

- name: Create inc folder
  with_items: "{{ lynchburg_assets.results }}"
  file:
    path: /var/www/{{ item.item.site_name }}/inc
    state: directory
  when: item.stat.isdir is undefined and item.item.lynchburg == true

- name: Create scss folder
  with_items: "{{ lynchburg_assets.results }}"
  file:
    path: /var/www/{{ item.item.site_name }}/inc/scss
    state: directory
  when: item.stat.isdir is undefined and item.item.lynchburg == true

- name: Create js folder
  with_items: "{{ lynchburg_assets.results }}"
  file:
    path: /var/www/{{ item.item.site_name }}/inc/js
    state: directory
  when: item.stat.isdir is undefined and item.item.lynchburg == true

- name: Create img folder
  with_items: "{{ lynchburg_assets.results }}"
  file:
    path: /var/www/{{ item.item.site_name }}/inc/img
    state: directory
  when: item.stat.isdir is undefined and item.item.lynchburg == true

- name: Create fonts folder
  with_items: "{{ lynchburg_assets.results }}"
  file:
    path: /var/www/{{ item.item.site_name }}/inc/fonts
    state: directory
  when: item.stat.isdir is undefined and item.item.lynchburg == true

- name: Create gulpfile.js
  with_items: "{{ lynchburg_gulpfile.results }}"
  template:
    src: gulpfile.js
    dest: /var/www/{{ item.item.site_name }}/gulpfile.js
  when: item.stat.exists is defined and item.stat.exists == false and item.item.lynchburg == true

N.B. If there's any other way to create the full folder structure easily without running five different tasks - one for each folder/subfolder - and someone could advise what that is, that'd also be appreciated!


回答1:


When lynchburg is false, the inc folder structure is created, however gulpfile.js isn't.

I know how to solve it, I don't know (yet) how to explain it:

Change the order of expressions in the conditional:

when: item.item.lynchburg == true and item.stat.isdir is undefined

For some reason:

when: dummy.key is undefined and false

and

when: false and dummy.key is undefined

give different results.

It works as expected only when checking the top-level variable (dummy is undefined).




回答2:


I seem to have fixed this in a moment of blind experimentation. I've removed the conditional check from the folder structure tasks, so it's just checking the raw vhosts loop, rather than looping through them first and then running the tasks on the results of the loop.

My tasks now look as follows, which seem to work exactly as I'd hope they would:

---
- name: Create inc folder
  with_items: "{{ vhosts }}"
  file:
    path: /var/www/{{ item.site_name }}/inc
    state: directory
  when: item.lynchburg == true

- name: Create scss folder
  with_items: "{{ vhosts }}"
  file:
    path: /var/www/{{ item.site_name }}/inc/scss
    state: directory
  when: item.lynchburg == true

- name: Create js folder
  with_items: "{{ vhosts }}"
  file:
    path: /var/www/{{ item.site_name }}/inc/js
    state: directory
  when: item.lynchburg == true

- name: Create img folder
  with_items: "{{ vhosts }}"
  file:
    path: /var/www/{{ item.site_name }}/inc/img
    state: directory
  when: item.lynchburg == true

- name: Create fonts folder
  with_items: "{{ vhosts }}"
  file:
    path: /var/www/{{ item.site_name }}/inc/fonts
    state: directory
  when: item.lynchburg == true

- name: Check if Lynchburg gulpfile.js has been previously created
  stat:
    path: /var/www/{{ item.site_name }}/gulpfile.js
  with_items: "{{ vhosts }}"
  when: item.lynchburg == true
  register: lynchburg_gulpfile

- name: Create gulpfile.js
  with_items: "{{ lynchburg_gulpfile.results }}"
  template:
    src: gulpfile.js
    dest: /var/www/{{ item.item.site_name }}/gulpfile.js
  when: item.stat.exists is defined and item.stat.exists == false and item.item.lynchburg == true 

I'll leave it to the community to tell me if this is correct or not but, as I say, it seems to work perfectly.




回答3:


It's possible I'm missing something, but it looks to me like the stat tasks and the conditional checks that go with them are unnecessary:

  • In the case of the folder structure, the first time the task runs, the directories will be created. But if it runs again on the same host, the tasks will be skipped, and you'll get output like this:

    localhost                  : ok=3    changed=0    unreachable=0    failed=0
    
  • In the case of the template task, you can set its force option to false which means the task won't run if the file already exists.

Finally, your folder structure can be created fairly easily in one task by using the with_nested style of loop (Ansible < 2.5), or a lookup (Ansible ≥ 2.5).

I'd recreate your playbook to look something like this (note that it will create the file structure in its own directory):

---
- hosts: localhost

  vars:
    vhosts:
      - site_name: sample
        lynchburg: true
      - site_name: sample2
        lynchburg: false

  tasks:
    - name: Create required folder structure.
      file:
        path: "{{ playbook_dir }}/var/www/{{ item.0.site_name }}/inc/{{ item.1 }}"
        state: directory
      with_nested:
        - "{{ vhosts }}"
        - ["scss", "img", "js", "fonts"]
      when: item.0.lynchburg

    - name: Template gulpfile into place.
      template:
        src: "{{ playbook_dir }}/gulpfile.js.j2"
        dest: "{{ playbook_dir }}/var/www/{{ item.site_name }}/gulpfile.js"
        force: false
      with_items: "{{ vhosts }}"
      when: item.lynchburg

Running this the first time creates the following result and folder structure. Note that:

  • Ansible reports two changed tasks:

     ____________
    < PLAY RECAP >
     ------------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    
    localhost                  : ok=3    changed=2    unreachable=0    failed=0
    
  • only the sample host directory and files are created.

    var
    └── www
        └── sample
            ├── gulpfile.js
            └── inc
                ├── fonts
                ├── img
                ├── js
                └── scss
    

If we run ansible-playbook playbook.yml again:

  • the folder and file structure is un-altered, and
  • Ansible reports zero changes:

     ____________
    < PLAY RECAP >
     ------------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    
    localhost                  : ok=3    changed=0    unreachable=0    failed=0
    


来源:https://stackoverflow.com/questions/42608284/ansible-2-conditionals-using-with-items-in-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!