Search code examples
jsonlistloopsansibleansible-inventory

How to loop through two lists & add conditional statement to execute something when one condition is true


I have a question, i got the sid list & the DB open_mode, i am trying to run a sql script on the DB when below two conditions satisfy:

  1. DB name should end with '1'.
  2. DB Open_Mode should be 'READ WRITE'.

i am using ansible dynamic inventory to get the sid's from the host & loop through that list, but i am unable to use the two conditions to work through the conditions i am adding.

- hosts: all
  gather_facts: false
  strategy: free
  tasks:
  - include_vars: roles/oracle/vars/install_vars.yaml
    vars:
     var_list:
        - script_name

  - set_fact:
      ORACLE_HOMES_DIR: "/u01/app/oracle/product"
      DB_HOME: "{{ ORACLE_HOMES_DIR }}/{{ ORACLE_VERSION }}/dbinst_1"

  - name: Copy script to host
    copy:
      src: "{{ playbook_dir }}/{{ script_name }}"
      dest: "/tmp/"
      owner: "{{ USER_ORACLE }}"
      group: "{{ GROUP_ORACLE }}"
      mode: 0755

  - name: Verify if the DB is open READ WRITE (or) not
    become_user: "{{ USER_ORACLE }}"
    environment:
      ORACLE_SID: "{{ sid }}"
      ORACLE_HOME: "{{ ORACLE_HOME }}"
    shell: "echo \"set pagesize 0\n select trim(open_mode) from v\\$database;\" | {{ORACLE_HOME}}/bin/sqlplus -S / as sysdba"
    with_items: "{{ hostvars[inventory_hostname]['sid_list'] }}"
    loop_control:
      loop_var: sid
    register: om

  - name: Get list of sid that are open in READ WRITE mode
    set_fact:
      sid_list: "{{ om.results | selectattr('sid','search','1$') | map (attribute='sid') | list }}"

  - name: Get the OPEN MODE output of the sid's from the list
    set_fact:
      om_out: "{{ om.results | selectattr('stdout') | map (attribute='stdout') | list }}"

  - name: execute sql script
    become_user: "{{ USER_ORACLE }}"
    environment:
      ORACLE_SID: "{{ item.0 }}"
      ORACLE_HOME: "{{ ORACLE_HOME }}"
    shell: "{{ ORACLE_HOME }}/bin/sqlplus / as sysdba @/tmp/{{ script_name }}"
    when: item.1 == 'READ WRITE'
    with_together:
      - "{{ sid_list }}"
      - "{{ om_out }}"

I am expected the playbook to execute the SQL script on the DB, but i am getting error saying "conditional result was False"

TASK [Get list of sid that are open in READ WRITE mode] ****************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:44
ok: [dwracdb1] => {
    "ansible_facts": {
        "sid_list": [
            "abhitest1",
            "dw1"
        ]
    },
    "changed": false
}

TASK [Get the SQL output from all the sid's] ***************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:48
ok: [dwracdb1] => {
    "ansible_facts": {
        "om_out": [
            "READ WRITE",
            "READ WRITE"
        ]
    },
    "changed": false
}

TASK [Print om out] ****************************************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:52
ok: [dwracdb1] => (item=[u'abhitest1', u'READ WRITE']) => {
    "msg": "sid output is abhitest1 om output is READ WRITE"
}
ok: [dwracdb1] => (item=[u'dw1', u'READ WRITE']) => {
    "msg": "sid output is dw1 om output is READ WRITE"
}

TASK [execute sql script] **********************************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:61
fatal: [dwracdb1]: FAILED! => {
    "msg": "The conditional check 'item.1 == 'READ WRITE'' failed. The error was: error while evaluating conditional (item.1 == 'READ WRITE'): 'item' is undefined\n\nThe error appears to have been in '/uhome/abhi/ansible/sql_script_execute.yaml': line 61, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n  - name: execute sql script\n    ^ here\n"
}

Solution

  • First, a formatting hint: move the when condition on your block up to the top so that it's obvious what it controls. When you put it at the bottom it's not obvious:

    - block:
      when:
        - hostvars[inventory_hostname]['sid_list'] is defined
    

    In this task, you're collecting multiple results (one for each entry in sid_list):

    - name: Verify if the DB is open READ WRITE (or) not
      become_user: "{{ USER_ORACLE }}"
      environment:
        ORACLE_SID: "{{ sid }}"
        ORACLE_HOME: "{{ ORACLE_HOME }}"
      shell: "echo \"set pagesize 0\n select trim(open_mode) from v\\$database;\" | {{ORACLE_HOME}}/bin/sqlplus -S / as sysdba"
      with_items: "{{ hostvars[inventory_hostname]['sid_list'] }}"
      loop_control:
        loop_var: sid
      register: om
    
    - name: Get list of sid that are open in READ WRITE mode
      set_fact:
        sid_list: "{{ om.results | selectattr('sid','search','1$') | map (attribute='sid') | list }}"
    

    That's why, when you run this task, you end up with a list of results:

    - name: Get the SQL output from all the sid's
      set_fact:
        om_out: "{{ om.results | selectattr(\"stdout\",'equalto','READ WRITE') | map (attribute='stdout') | list }}"
    

    You're doing the correct thing here in your debug task using with_together: you need that in order to associate a result in om_out with one of the entries in sid_list:

    - name: Print om out
      debug:
       msg: sid output is {{ item.0 }} om output is {{ item.1 }}
      with_together:
        - "{{ sid_list }}"
        - "{{ om_out }}"
    

    You should do the same thing when trying to execute your sql script. Get rid of the block, because you only have a single task and you can't loop a block:

      - name: execute sql script
        become_user: "{{ USER_ORACLE }}"
        environment:
          ORACLE_SID: "{{ sid.0 }}"
          ORACLE_HOME: "{{ ORACLE_HOME }}"
        shell: "{{ ORACLE_HOME }}/bin/sqlplus / as sysdba @/tmp/{{ script_name }}"
        when:
          - sid.1 == 'READ WRITE'
        with_together:
          - "{{ sid_list }}"
          - "{{ om_out }}"
        loop_control:
          loop_var: sid
    

    In this loop, sid.0 will be the value from sid_list, and sid.1 will be the corresponding value from om_out.