Viscosity
Viscosity

Reputation: 321

How to use a variable defined in a previous task for use in a task where the conditional omits that host?

Effectively, I have two servers, and I am trying to get use output from the command of one of them, to configure the other, and vise versa. I spent a few hours reading on this, and found out that the hostvars process and dummy hosts is seemingly what I want. No matter how I try to implement this process, I still get undefined variables, and/or failures from the host(s) not being in the pattern for the task:

Here is the relevant block, with only hosts mux-ds1 and mux-ds2 are in the dispatchers group:

---
 - name: Play that sets up the sql database during the build process on all mux dispatchers.
   hosts: mux_dispatchers
   remote_user: ansible
   vars:
     ansible_ssh_pipelining: yes

   tasks:

     - name: Check and save database master bin log file and position on mux-ds2.
       shell: sudo /usr/bin/mysql mysql -e "show master status \G" | grep -E 'File:|Position:' | cut -d{{':'}} -f2 | awk '{print $1}'
       become: yes
       become_method: sudo
       register: syncds2
       when: ( inventory_hostname == 'mux-ds2' )

     - name: Print current ds2 database master bin log file.
       debug:
         var: "syncds2.stdout_lines[0]"

     - name: Print current ds2 database master bin position.
       debug:
         var: "syncds2.stdout_lines[1]"

     - name: Add mux-ds2 some variables to a dummy host allowing us to use these variables on mux-ds1.
       add_host:
         name: "ds2_bin"
         bin_20: "{{ syncds2.stdout_lines }}"

     - debug:
         var: "{{ hostvars['ds2_bin']['bin_21'] }}"

     - name: Compare master bin variable output for ds1's database and if different, configure for it.
       shell: sudo /usr/bin/mysql mysql -e "stop slave; change master to master_log_file='"{{ hostvars['ds2_bin']['bin_21'][0] }}"', master_log_pos="{{ hostvars['ds2_bin']['bin_21'][1] }}"; start slave"
       become: yes
       become_method: sudo
       register: syncds1
       when: ( inventory_hostname == 'mux-ds1' )

Basically everything works properly up to where I try to see the value of the variable from the dummy host with the debug module, but it tells me the variable is still undefined even though it's defined in the original variable. This is supposed to be the system to get around such problems:

TASK [Print current ds2 database master bin log file.] **************************************************
ok: [mux-ds1] => {
    "syncds2.stdout_lines[0]": "VARIABLE IS NOT DEFINED!"
}
ok: [mux-ds2] => {
    "syncds2.stdout_lines[0]": "mysql-bin.000001"
}

TASK [Print current ds2 database master bin position.] **************************************************
ok: [mux-ds1] => {
    "syncds2.stdout_lines[1]": "VARIABLE IS NOT DEFINED!"
}
ok: [mux-ds2] => {
    "syncds2.stdout_lines[1]": "107"
}

The above works as I intend, and has the variables populated and referenced properly for mux-ds2.

TASK [Add mux-ds2 some variables to a dummy host allowing us to use these variables on mux-ds1.] ********
fatal: [mux-ds1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to be in '/home/ansible/ssn-project/playbooks/i_mux-sql-config.yml': line 143, column 8, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n     - name: Add mux-ds2 some variables to a dummy host allowing us to use these variables on mux-ds1.\n       ^ here\n"}

This is where the issue is, the variable seems to be magically undefined again, which is odd given this process is designed to end-run that issue. I can't even make it to the second set of debug tasks.

Note that this is ultimately for the purpose of syncing up two master/master replication mysql databases. I'm also doing this with the shell module because the mysql version which must be used can be no higher than 5.8, and the ansible module requires 5.9, which is a shame. There same process will be done for mux-ds2 in reverse as well assuming this can be made to work.

Either I'm making a mistake in this implementation which keeps it from functioning, or I'm using the wrong implementation for what I want. I've spent too much time now trying to figure this out alone and would appreciate any solution for this which would work. Thanks in advance!

Upvotes: 1

Views: 1403

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39264

Seems like you are going a complicated route when a simple delegation of tasks and the usage of the special variable hostvars, to be able to fetch fact from different node, should give you what you expect.

Here is an example — focusing just on the important part — so, you might want to add the become and become_user back in there:

- shell: >-
    sudo /usr/bin/mysql mysql -e "show master status \G" 
    | grep -E 'File:|Position:' 
    | cut -d{{':'}} -f2 
    | awk '{print $1}'
  delegate_to: mux-ds2
  run_once: true
  register: syncds2

- shell: >-
    sudo /usr/bin/mysql mysql -e "stop slave; 
      change master to 
      master_log_file='"{{ hostvars['mux-ds2'].syncds2.stdout_lines.0 }}"', 
      master_log_pos="{{ hostvars['mux-ds2'].syncds2.stdout_lines.1 }}"; 
      start slave"
  delegate_to: mux-ds1
  run_once: true

Here is an example, running some dummy shell tasks, given the playbook:

- hosts: node1, node2
  gather_facts: no

  tasks:
    - shell: |
        echo 'line 0'
        echo 'line 1'
      delegate_to: node2
      run_once: true
      register: master_config

    - shell: |
        echo '{{ hostvars.node2.master_config.stdout_lines.0 }}'
        echo '{{ hostvars.node2.master_config.stdout_lines.1 }}'
      delegate_to: node1
      run_once: true
      register: master_replicate_config

    - debug:
        var: master_replicate_config.stdout_lines
      delegate_to: node1
      run_once: true

This would yield:

PLAY [node1, node2] **********************************************************

TASK [shell] *****************************************************************
changed: [node1 -> node2(None)]

TASK [shell] *****************************************************************
changed: [node1]

TASK [debug] *****************************************************************
ok: [node1] => 
  master_replicate_config.stdout_lines:
  - line 0
  - line 1

Upvotes: 1

Related Questions