Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set an Ansible variable for all plays/hosts?

Tags:

ansible

This question is NOT answered. Someone mentioned environment variables. Can you elaborate on this?

This seems like a simple problem, but not in ansible. It keeps coming up. Especially in error conditions. I need a global variable. One that I can set when processing one host play, then check at a later time with another host. In a nutshell, so I can branch later in the playbook, depending on the variable.

We have no control over custom software installation, but if it is installed, we have to put different software on other machines. To top it off, the installations vary, depending on the VM folder. My kingdom for a global var.

The scope of variables relates ONLY to the current ansible_hostname. Yes, we have group_vars/all.yml as globals, but we can't set them in a play. If I set a variable, no other host's play/task can see it. I understand the scope of variables, but I want to SET a global variable that can be read throughout all playbook plays. The actual implementation is unimportant but variable access is (important).

My Question: Is there a way to set a variable that can be checked when running a different task on another host? Something like setGlobalSpaceVar(myvar, true)? I know there isn't any such method, but I'm looking for a work-around. Rephrasing: set a variable in one tasks for one host, then later in another task for another host, read that variable.

The only way I can think of is to change a file on the controller, but that seems bogus.

An example

The following relates to oracle backups and our local executable, but I'm keeping it generic. For below - Yes, I can do a run_once, but that won't answer my question. This variable access problem keeps coming up in different contexts.

I have 4 xyz servers. I have 2 programs that need to be executed, but only on 2 different machines. I don't know which. The settings may be change for different VM environments.

Our programOne is run on the server that has a drive E. I can find which server has drive E using ansible and do the play accordingly whenever I set a variable (driveE_machine). It only applies to that host. For that, the other 3 machines won't have driveE_machine set. In a later play, I need to execute another program on ONLY one of the other 3 machines. That means I need to set a variable that can be read by the other 2 hosts that didn't run the 2nd program. I'm not sure how to do it.

Inventory file:

[xyz]
serverxyz[1:4].private.mystuff

Playbook example:

---
- name: stackoverflow variable question
  hosts: xyz
  gather_facts: no
  serial: 1
  tasks:
      - name: find out who has drive E
         win_shell: dir e:\
         register: adminPage
         ignore_errors: true

       # This sets a variable that can only be read for that host
      - name: set fact driveE_machine when rc is 0
        set_fact:
           driveE_machine: "{{inventory_hostname}}"
        when: adminPage.rc == 0

       - name: run program 1
         include: tasks/program1.yml
         when: driveE_machine is defined

       # program2.yml executes program2 and needs to set some kind of variable
       # so this include can only be executed once for the other 3 machines 
       # (not one that has driveE_machine defined and ???
       - name: run program 2
         include: tasks/program2.yml
         when: driveE_machine is undefined and ???
         # please don't say run_once: true - that won't solve my variable access question

Is there a way to set a variable that can be checked when running a task on another host?

like image 756
older coder Avatar asked Nov 07 '17 21:11

older coder


People also ask

How do I control Ansible playbook only on specific hosts?

Using the --limit parameter of the ansible-playbook command is the easiest option to limit the execution of the code to only one host. The advantage is that you don't need to edit the Ansible Playbook code before executing to only one host.

How do I Group hosts in Ansible?

Ansible uses a combination of a hosts file and a group_vars directory to pull variables per host group and run Ansible plays/tasks against hosts. group_vars/all is used to set variables that will be used for every host that Ansible is ran against.


1 Answers

No sure what you actually want, but you can set a fact for every host in a play with a single looped task (some simulation of global variable):

playbook.yml

---
- hosts: mytest
  gather_facts: no
  vars:
  tasks:
    # Set myvar fact for every host in a play
    - set_fact:
        myvar: "{{ inventory_hostname }}"
      delegate_to: "{{ item }}"
      with_items: "{{ play_hosts }}"
      run_once: yes
    # Ensure that myvar is a name of the first host
    - debug:
        msg: "{{ myvar }}"

hosts

[mytest]
aaa ansible_connection=local
bbb ansible_connection=local
ccc ansible_connection=local

result

PLAY [mytest] ******************
META: ran handlers

TASK [set_fact] ******************
ok: [aaa -> aaa] => (item=aaa) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "aaa"}
ok: [aaa -> bbb] => (item=bbb) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "bbb"}
ok: [aaa -> ccc] => (item=ccc) => {"ansible_facts": {"myvar": "aaa"}, "ansible_facts_cacheable": false, "changed": false, "failed": false, "item": "ccc"}

TASK [debug] ******************
ok: [aaa] => {
    "msg": "aaa"
}
ok: [bbb] => {
    "msg": "aaa"
}
ok: [ccc] => {
    "msg": "aaa"
}
like image 75
Konstantin Suvorov Avatar answered Nov 13 '22 07:11

Konstantin Suvorov