linuxansibleansible-factsansible-template

How to use only one variable out of 3 based on condition in ansible?


I have three variables to be register based on condition, it will run one task and register one variable, how can i use testing variable for respective task ?

---
- name: Test1
  command: "echo HAHA"
  register: testing
  when: HAHA is defined

- name: Test2
  command: "echo BLABLA"
  register: testing
  when: BLABLA is defined

- name: Test3
  command: "echo DODO"
  register: testing
  when: DODO is defined
  
- name: Verify Tests
  command: "execute {{ testing.stdout }}"
  when: TEST is defined

I got an error like undefined varible like below:

{"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/home/ubuntu/tests/': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Verify Tests \n  ^ here\n"

Could you please suggest ?


Solution

  • It's always a good idea to use debug task to verify that your variables contain the content you think they do.

    When you use register in a task, it always sets the named variable, whether the task runs or not. This is because the registered value includes information about the execution status of the task. For example, if variable DODO is not set, then in your final task, the variable testing will contain:

    ok: [localhost] => {
        "testing": {
            "changed": false,
            "false_condition": "DODO is defined",
            "skip_reason": "Conditional result was False",
            "skipped": true
        }
    }
    

    As you can see, there is no stdout attribute here. For the behavior you want, you could rewrite you playbook like this:

    - hosts: localhost
      gather_facts: false
      tasks:
      - name: Test1
        command: "echo HAHA"
        register: testing1
        when: HAHA is defined
    
      - name: Test2
        command: "echo BLABLA"
        register: testing2
        when: BLABLA is defined
    
      - name: Test3
        command: "echo DODO"
        register: testing3
        when: DODO is defined
    
      - set_fact:
          testing: >-
            {{
              [testing1, testing2, testing3] | selectattr("stdout", "defined")
            }}
        
      - name: Verify Tests
        when: testing
        debug:
          msg: "execute {{ testing[0].stdout }}"
    

    Running this with no variables defined results in:

    TASK [Verify Tests] *************************************************************************************************************************
    skipping: [localhost]
    

    But if we define the target variables:

    $ ansible-playbook playbook.yaml -e DODO=1
    .
    .
    .
    TASK [Verify Tests] *************************************************************************************************************************
    ok: [localhost] => {
        "msg": "execute DODO"
    }
    

    Or:

    $ ansible-playbook playbook.yaml -e HAHA=1
    .
    .
    .
    TASK [Verify Tests] *************************************************************************************************************************
    ok: [localhost] => {
        "msg": "execute HAHA"
    }
    

    If multiple variables are set, you will get the value from the first task to execute:

    $ ansible-playbook playbook.yaml -e HAHA=1 -e DODO=1
    .
    .
    .
    TASK [Verify Tests] *************************************************************************************************************************
    ok: [localhost] => {
        "msg": "execute HAHA"
    }