4
votes

My Ansible playbook deploys to both database and webservers and I need to use some shared variables between them. The answer from this question almost gives me what I need:

---
- hosts: all
  tasks:
  - set_fact: my_global_var='hello'

- hosts: db
  tasks:
  - debug: msg={{my_global_var}}

- hosts: web
  tasks:
  - debug: msg={{my_global_var}}

However, in my case the variable is a password that is generated randomly by the playbook on each run and then has to be shared:

---
- hosts: all
  tasks:
  - name: Generate new password
    shell: "tr -dc _[:alnum:] < /dev/urandom | head -c${1:-20}"
    register: new_password    
  - name: Set password as fact
    set_fact:
      my_global_var: "{{ new_password.stdout }}"

- hosts: db
  tasks:
  - debug: msg={{my_global_var}}

- hosts: web
  tasks:
  - debug: msg={{my_global_var}}

This above example doesn't work as the password is now re-generated and completely different for each host in the all hosts (unless you coincidentally use the same machine/hostname for your db and web servers).

Ideally I don't want someone to have to remember to pass a good random password in on the command-line using --extra-vars, it should be generated and handled by the playbook.

Is there any suggested mechanism in Ansible for creating variables within a playbook and having it accessible to all hosts within that playbook?

2

2 Answers

3
votes

You may want to try to generate pass on localhost and then copy it to every other host:

---
- hosts: localhost
  tasks:
  - name: Generate new password
    shell: "tr -dc _[:alnum:] < /dev/urandom | head -c${1:-20}"
    register: new_password    

- hosts: all
  tasks:
  - name: Set password as fact
    set_fact:
      my_global_var: "{{ hostvars['localhost'].new_password.stdout }}"

- hosts: db
  tasks:
  - debug: msg={{my_global_var}}

- hosts: web
  tasks:
  - debug: msg={{my_global_var}}
0
votes

I know this is an old question but I settled on an alternative method that combines the two answers provided here and this issue, by using an implicit localhost reference and doing everything within the same play. I think it's a bit more elegant. Tested with 2.8.4.

This is the working solution in my context, where I wanted a common timestamped backup directory across all my hosts, for later restore:

---
tasks:
  - name: Set local fact for the universal backup string
    set_fact:
      thisHostTimestamp: "{{ ansible_date_time.iso8601 }}"
    delegate_to: localhost
    delegate_facts: true

  - name: Distribute backup datestring to all hosts in group
     set_fact:
       backupsTimeString: "{{ hostvars['localhost']['thisHostTimestamp'] }}"

I believe this should translate to the OP's original example like this, but I have not tested it:

---
- hosts: all
  tasks:
  - name: Generate new password
    shell: "tr -dc _[:alnum:] < /dev/urandom | head -c${1:-20}"
    register: new_password  
    delegate_to: localhost
    delegate_facts: true

  - name: Set password as fact
    set_fact:
      my_global_var: "{{ hostvars['localhost'].new_password.stdout }}"