Ansible complex when statement - part of it is not

2019-02-21 05:02发布

问题:

I have got an issue with a "when" statement on an Ansible playbook. Here is the task :

- name: Testing port 80 - 443 - 8443 on server_x
  wait_for: host=server_x port={{item}} timeout=1
  with_items:
    - 80
    - 443
    - 8443
  when: (sg_building == "TIGERY" and sg_marley_environment == "DEV" and sg_building is defined and sg_marley_environment is defined) or (specified_building == "TIGERY" and specified_environment == "DEV" and specified_building is defined and specified_environment is defined)

sg_building and sg_marley_inventory are defined on the dynamic inventory.

specified_inventory and specified_environment is defined with extra-vars (-e with the ansible-playbook command)

The first part of the when statement works fine (everything before the "or"), however the second part is just skipped (I've tried to switch place and it confirmed it)

Do you have any idea why the "or" is not working as expected ?

Thank you for you help !

回答1:

Avoid is defined in complex expressions, because it is not actually a Jinja2 test, but a catch for undefined error.
Read this comment for details.

You may have more luck with:

when: (sg_building | default('') == "TIGERY" and sg_marley_environment | default('') == "DEV") or (specified_building | default('') == "TIGERY" and specified_environment | default('') == "DEV")


回答2:

On the meantime, I found another solution by setting an empty vars on the beginning of the playbook if the other variable is defined. Then, I'm just doing my test without is defined

- name: Set empty SG building vars if specified_building is set
  set_fact: sg_building=""
  when: specified_building is defined

- name: Set empty SG env vars if specified_environment is set
  set_fact: sg_marley_environment""
  when: specified_environment is defined

- name: Set empty specified_building vars if sg_building is set
  set_fact: specified_building=""
  when: sg_building is defined

- name: Set empty specified_environment vars if sg_marley_environment is set
  set_fact: specified_environment=""
  when: sg_marley_environment is defined

- name: Testing port 80 - 443 - 8443 on server_x
  wait_for: host=server_x port={{item}} timeout=1
  with_items:
   - 80
   - 443
   - 8443
  when: (sg_building == "TIGERY" and sg_marley_environment == "DEV") or (specified_building == "TIGERY" and specified_environment == "DEV")

@Konstantin Suvorov : I'm gonna try your solution as it seems more elegant



回答3:

just tried it out:

- hosts: bidman
  remote_user: deploy
  tasks:
    - debug: msg="test"
      when: (sg_building == "TIGERY"
         and sg_marley_environment == "DEV"
         and sg_building is defined
         and sg_marley_environment is defined)
       or (specified_building == "TIGERY"
         and specified_environment == "DEV"
         and specified_building is defined
         and specified_environment is defined)

Command line

ansible-playbook test.yml -i hosts/test -e specified_building=TIGERY -e specified_environment=DEV

The task is executed if the extra-vars are correctly set.

Which ansible version do you use?

-- Added 2017/05/12

Hi, please change the order of the statements like this:

- hosts: bidman
  remote_user: deploy
  tasks:
    - debug: msg="test"
      when: (sg_building is defined
         and sg_marley_environment is defined
         and sg_building == "TIGERY"
         and sg_marley_environment == "DEV")
       or (specified_building is defined
         and specified_environment is defined
         and specified_building == "TIGERY"
         and specified_environment == "DEV")

So that the ... if defined is before the actual check of the varaible. This will do the trick.