Getting Started With Ansible - Part Eight

In this article, we will learn about various types of variables and their precedence in Ansible.

This is in continuation of the articles of the series “Learning Ansible”. In our previous articles, we have learned about loops, variables, and their precedence.
 
In this article, we will be covering the below topics.
  • Introduction to Variables 
  • Playbook Variables 
  • Command-line Variables 
  • Variables in group_vars 
  • Variables Precedence with examples 
    • Variables defined inside playbook 
    • Variables defined inside group_vars/all 
    • Variables defined inside group_vars/groupname 
    • Variables defined inside host_vars/hostname 
    • Overwriting variables with command-line arguments
Let’s get started now.
 

Introduction to Variables

 
Before we discuss variables, why do you think we need variables?
 
Reusability is one of the most important reasons for using variables in a playbook. We are going to update the existing playbook show above and we will replace the static values with the variables.
 
We have seen different types of variables like,
  • Inventory variables 
  • Fact variables 
  • Loop variables

Playbook Variables 


Here, we are going to see Custom variables which we can define inside the playbook.
 
Below is the updated playbook code with some custom variables that defined using vars keyword.
  1. ---  
  2. - name: Display Database Setup and variables  
  3. hosts: DBServerGroup  
  4. become: yes  
  5. gather_facts: False  
  6. vars:  
  7. dbName: myFirstDB  
  8. dbUser: admin  
  9. dbPassword: '12345'  
  10. tasks:  
  11. - name: Install Mariadb and other tools  
  12. yum:  
  13. name: "{{item}}"  
  14. state: present  
  15. loop:  
  16. - mariadb-server  
  17. - MySQL-python  
  18. - unzip  
  19. - git  
  20. - wget  
  21. - name: Add list of users  
  22. user:  
  23. name: "{{item}}"  
  24. state: present  
  25. loop:  
  26. - amit  
  27. - ankit  
  28. - sumit  
  29. - rohit  
  30. - name: Start and Enable Mariadb service  
  31. service:  
  32. name: mariadb  
  33. state: started  
  34. enabled: yes  
  35. - name: Create a new database with name "myFirstDB"  
  36. mysql_db:  
  37. name: "{{dbName}}"  
  38. state: present  
  39. - name: Create user in database with name "admin"  
  40. mysql_user:  
  41. name: "{{dbUser}}"  
  42. password: "{{dbPassword}}"  
  43. priv: '*.*:ALL'  
  44. state: present  
OUTPUT
 
Ansible
 
So, we can see that the playbook has executed successfully.
 

Command line Variables

 
We can also overwrite the variables defined inside the playbook using the command line.
 
Command-line variables have higher priority than playbook variables. So, let’s create a new database by giving a different name through the command line.
  1. ansible-playbook db.yml -e dbName=mySecondDB  
OUTPUT
 
Ansible
 
So, we can see, changed=1 means it has created a new database with the name mySecondDB.
 

Variables in Group_Vars

 
Variables defined in the Group vars have lower priority than playbook variables. So, let’s create a directory called group_vars and define all our variables there which we just defined in the playbook.
  1. mkdir group_vars  
  2. vim group_vars/all  
and add the below variables.
  1. dbName: myFirstDB  
  2. dbUser: admin  
  3. dbPassword: '12345'  
Ansible
 
Then, remove the variables defined in the playbook. Below is the updated playbook.
  1. ---  
  2. - name: Display Database Setip and variables  
  3. hosts: DBServerGroup  
  4. become: yes  
  5. gather_facts: False  
  6. tasks:  
  7. - name: Install Mariadb and other tools  
  8. yum:  
  9. name: "{{item}}"  
  10. state: present  
  11. loop:  
  12. - mariadb-server  
  13. - MySQL-python  
  14. - unzip  
  15. - git  
  16. - wget  
  17. - name: Add list of users  
  18. user:  
  19. name: "{{item}}"  
  20. state: present  
  21. loop:  
  22. - amit  
  23. - ankit  
  24. - sumit  
  25. - rohit  
  26. - name: Start and Enable Mariadb service  
  27. service:  
  28. name: mariadb  
  29. state: started  
  30. enabled: yes  
  31. - name: Create a new database with name "myFirstDB"  
  32. mysql_db:  
  33. name: "{{dbName}}"  
  34. state: present  
  35. - name: Create user in database with name "admin"  
  36. mysql_user:  
  37. name: "{{dbUser}}"  
  38. password: "{{dbPassword}}"  
  39. priv: '*.*:ALL'  
  40. state: present  
OUTPUT
 
Ansible
 
So, it has executed successfully without any errors.
 
NOTE
Ansible first looks for variables in the playbook and if not found, it goes and checks the variables if they are defined in the group_vars. If there also, Ansible doesn’t find, then it will give you the error as variables not defined.
 
So above, we have seen that our playbook executed successfully, but how do you know from where it has picked the variables as variables can be defined at multiple places?
 

Variables Precedence with examples

 
Whenever the module gets executed in ansible it returns the output in JSON format and if we want to keep that JSON output we can use register in playbook.
 
We can use the ansible module debug to print the value of variables.
 
Case 1 - Variables defined inside the playbook
 
In this example below, we have defined two variables username and comment in the playbook.
 
We will create a new playbook named precedence.yml and write the below code.
  1. ---  
  2. - hosts: all  
  3. vars:  
  4. userName: playbookUser  
  5. Comment: User from playbook  
  6. tasks:  
  7. - name: Create User  
  8. user:  
  9. name: "{{userName}}"  
  10. comment: "{{Comment}}"  
  11. register: user_output  
  12. - debug:  
  13. var: user_output  
OUTPUT
 
Ansible
 
And we can see from the output that user has been added successfully on all servers and debug module has printed user_output variable with the details. To further refine the output, we can add only those keys which we really want to see. So, we will add name and comment in the debug module.
  1. ---  
  2. - hosts: all  
  3. vars:  
  4. userName: playbookUser  
  5. Comment: User from playbook  
  6. tasks:  
  7. - name: Create User  
  8. user:  
  9. name: "{{userName}}"  
  10. comment: "{{Comment}}"  
  11. register: user_output  
  12. - debug:  
  13. var: user_output.name  
  14. - debug:  
  15. var: user_output.comment  
OUTPUT
 
Ansible
 
We can see now that variables are being used from the playbook with the help of the debug module.
 
Case 2 - Variables defined inside group_vars/all
 
Now let’s remove the variables earlier defined in the playbook and define them inside the group_vars/all.
 
Below is the updated group_vars/all file,
  1. dbName: myFirstDB  
  2. dbUser: admin  
  3. dbPassword: '12345'  
  4. userName: commonUser  
  5. Comment: user fom group_vars/all file  
And Below is the updated playbook,
  1. ---  
  2. - hosts: all  
  3. tasks:  
  4. - name: Create User  
  5. user:  
  6. name: "{{userName}}"  
  7. comment: "{{Comment}}"  
  8. register: user_output  
  9. - debug:  
  10. var: user_output.name  
  11. - debug:  
  12. var: user_output.comment  
OUTPUT
 
Ansible
 
We can see that the variables in the playbook have been picked from the group_vars/all and that can be seen in the output.
 
Case 3 - Variables defined inside group_vars/groupname
 
Ansible 
 
From our existing inventory file, we can see different groups defined.
 
Group vars and Host vars are inventory specific variables. Now suppose we need separate variables for WebServersGroup. So, I will create a file with the name of a group with the below command. 
  1. vim group_vars/ WebServersGroup  
with the same variable names but different values to show you the precedence.
 
Ansible
 
Now let’s run the playbook to see the variable precedence.
 
Ansible
 
We can see that for the web servers the variables are being taken from the group-specific files while for the Db server it comes from the group_vars/all file.
 
Case 4 - Variables defined inside host_vars/hostname
 
Now suppose for Web Server 03 we need other values of the variables that we have earlier used for the entire group.
 
For that, we will make a new directory with the below command.
  1. mkdir host_vars  
Then create a new file with the web server name
  1. vim vars/websrv03  
And add the below code.
  1. userName: webServer3User  
  2. Comment: Variable from host_vars file  
Ansible
 
Now we can see that we have defined the same variables at 3 places with different values.
 
Ansible
 
So, for web server 03 it will pick the value from the host_vars/websrv03 file and for web server 01 and 02 it will pick from group_vars/WebServersGroup and for database server 01 it will pick from group_vars/all file.
 
Ansible
 
Great... 😊 we got the right results with correct precedence.
 
Case 5 - Overwriting variables with command-line arguments
 
And again, we can overwrite the variables through thecommand line using -e option 
  1. ansible-playbook precedence.yml -e userName=CommandUser -e Comment=CreatedUsingCommandLine  
Ansible
 
From the output, as the command line variables have the highest precedence, we can see that all our servers have got the values of the variables from the command line.
 

Summary

 
In this article, we have learned and seen some cool practical examples of variables and their order of precedence. In the next article in this series, we will be learning some more concepts.
 
I hope you find this article helpful. Stay tuned for more … Cheers!!
 
You can also check out some of my previous articles of the series “Learning Ansible” here,