Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible increment variable globally for all hosts

Tags:

ansible

I have two servers in my inventory (hosts)

[server]
10.23.12.33
10.23.12.40

and playbook (play.yml)

---
- hosts: all
  roles:
    web

Inside web role in vars directory i have main.yml

---
file_number : 0

Inside web role in tasks directory i have main.yml

---
- name: Increment variable
  set_fact: file_number={{ file_number | int + 1 }}

- name: create file
  command: 'touch file{{ file_number }}'

Now i expect that in first machine i will have file1 and in second machine i will have file2 but in both machines i have file1

So this variable is local for every machine, how could i make it global for all machines.

My file structure is:

hosts
play.yml
roles/
  web/
    tasks/
      main.yml
    vars/
      main.yml
like image 347
Nasr Avatar asked Dec 13 '15 17:12

Nasr


1 Answers

Now i expect that in first machine i will have file1 and in second machine i will have file2 but in both machines i have file1

You need to keep in mind that variables in Ansible aren't global. Variables (aka 'facts') are applied uniquely to each host, so file_number for host1 is different than file_number for host2. Here's an example based loosely on what you posted:

roles/test/vars/main.yml:

---
file_number: 0

roles/test/tasks/main.yml:

---
- name: Increment variable
  set_fact: file_number={{ file_number | int + 1 }}

- name: debug
  debug: msg="file_number is {{ file_number }} on host {{ inventory_hostname }}"

Now suppose you have just two hosts defined, and you run this role multiple times in a playbook that looks like this:

---
- hosts: all
  roles:
    - { role: test }

- hosts: host1
  roles:
    - { role: test }

- hosts: all
  roles:
    - { role: test }

So in the first play the role is applied to both host1 & host2. In the second play it's only run against host1, and in the third play it's again run against both host1 & host2. The output of this playbook is:

PLAY [all] ********************************************************************

TASK: [test | Increment variable] *********************************************
ok: [host1]
ok: [host2]

TASK: [test | debug] **********************************************************
ok: [host1] => {
    "msg": "file_number is 1 on host host1"
}
ok: [host2] => {
    "msg": "file_number is 1 on host host2"
}

PLAY [host1] **************************************************

TASK: [test | Increment variable] *********************************************
ok: [host1]

TASK: [test | debug] **********************************************************
ok: [host1] => {
    "msg": "file_number is 2 on host host1"
}

PLAY [all] ********************************************************************

TASK: [test | Increment variable] *********************************************
ok: [host1]
ok: [host2]

TASK: [test | debug] **********************************************************
ok: [host1] => {
    "msg": "file_number is 3 on host host1"
}
ok: [host2] => {
    "msg": "file_number is 2 on host host2"
}

So as you can see, the value of file_number is different for host1 and host2 since the role that increments the value ran against host1 more times than it did host2.

Unfortunately there really isn't a clean way making a variable global within Ansible. The entire nature of Ansible's ability to run tasks in parallel against large numbers of hosts makes something like this very tricky. Unless you're extremely careful with global variables in a parallel environment you can easily trigger a race condition, which will likely result in unpredictable (inconsistent) results.

like image 139
Bruce P Avatar answered Oct 01 '22 23:10

Bruce P