Separating site‑specific code from static code is known as decoupling.
So you should always have your playbooks to be as flexible as you can,
and then if somebody else wants to use them,
all they need to do is change the variables.
So with Ansible,
you could execute tasks and playbooks on multiple systems with a single command.
There will always be some variations in the machines that Ansible is managing,
and Ansible uses variables to manage the differences between the systems.
To represent the variations among the systems,
we can create variables with the standard YAML syntax,
including lists and dictionaries.
So there are several places where you can define all of these variables.
You can define these variables in your playbooks,
inventory, reusable files, or roles, and even at the command line.
During a playbook run,
you can also create variables by registering a tasks
return value or values as a new variable.
After creating variables,
you can then use those variables in module arguments
such as with conditional when clauses, templates,
and loops.
So we looked at defining variables in inventory,
but now let us look at the other places where we can define our variables.
The simplest way to define variables is to put a Vars: section in your
playbook with the name and values of the variable.
This allows you to define several configuration‑related variables.
So to define variables in plays,
we include a Vars: section in the header of the play,
where the variables are needed.
So variables defined in plays are only valid within that
specific play and won't have playbook scope.
So if you need a variable in a different play,
you need to define it again, and this may be inconvenient for you.
We also have the set_fact,
which is a module that can be used anywhere in a play to set variables.
Any variable set in this way applies to a fact of a machine in which it's set.
So the set_fact relates to variables to the host used in the play.
Here you can dynamically set variables based on the
result of any task in the playbook.
So the set_fact is dynamically defining variables and will have playbook scope.
You can also put variables into one or more files
using the section called Vars_files.
This allows you to put variables in a file instead of directly in the playbook.
More importantly,
this allows you to separate variables that contain sensitive information.
So when you define variables in reusable variable files,
the sensitive variables are separated from the playbook.
This separation allows you to store your playbooks in,
for example,
source‑controlled software system and then even share the
playbooks without the risk of exposing any passwords or
other sensitive or personal data.
So, Ansible allows you to put variables into one or more files,
which are then referenced in the playbook using the vars_files.
So using the vars_files to specify a list of files that
include variables you want to include,
which is convenient when you want to manage variables
independently from the place of using them.
This may be really useful for the purposes of security.
We also have the Vars_prompt in the play header.
That is used to prompt users for a variable value, and this has playbook scope.
By default,
the variable is flagged as private so the user does not see
anything when they're entering the variable.
We can also set this to private know if you want to.
So as already mentioned, when we were in a playbook,
we can define variables passing at the command line too.
And this is used with the ‑‑extra‑vars argument or the ‑e.
Task variables are made from data that has been discovered while
executing tasks or in the fact‑gathering phase of a play.
These variables are host specific and they're added to the hosts host var.
Variables of this type can be discovered via gather facts or the fact module
populated from tasks return data via registered task key or defined directly
by a task using the set_fact or at host modules.
So facts are system variables that contain information about managed systems.
Each playbook starts with an implicit task to
gather facts automatically for you.
This can, if you want, be disabled in the play head.
Keep in mind that gathering facts can take some time,
and if you're not going to use them, you may want to disable this,
and we will demo this too.
So as you know, we can also gather facts manually,
and this is used by the setup module.
So all of these facts are stored in one big variable called Ansible_facts.
However, within this variable, we will obviously have second‑tier variables,
so all of these facts are categorized into different variables.
So these facts are variables, and you can use these facts in,
for example, conditional and when statements.
And we will also demo this relatively soon.
So as already mentioned,
fact gathering can take some time and especially if you're working
against many hosts and have a large environment.
And here we can set up a fact cache if you want to.
So if fact caching is enabled,
Ansible will store facts in a cache for the first time it connects to the host.
This is then added in your ansible.cfg file with the fact_caching_timeoutvalue.
So if your playbook does not reference any Ansible facts,
honestly, you can turn off fact gathering for that play,
and here we can use the gather_facts clause in the play and in the ansible.cfg.
So just before we finish up this section,
I just want to summarize the different ways that we
can define variables in Ansible.
You can define variables in the play header using the vars: section,
also in the play header including the vars_files.
We can use the set_fact module.
We also have the option of using the command line
with the ‑e key value argument.
We also have inventory at variables.
We can have host or group variables in inventory.
We can also have the Vars_prompt to request values from
the user while running the playbook.
Finally, we have facts, which are discovered variables,
and they contain system properties.