Sometimes it is important to set and get variables in a playbook.
Very often, you'll need to automate multiple similar operations. In those cases, you'll want to create a single playbook that can be called with different variables to ensure code reusability.
Another case where variables are very important is when you have more than one datacenter and some values will be datacenter-specific. A common example are the DNS servers. Let's analyze the following simple code that will introduce us to the Ansible way to set and get variables:
---
- hosts: all
remote_user: fale
tasks:
- name: Set variable 'name'
set_fact:
name: Test machine
- name: Print variable 'name'
debug:
msg: '{{ name }}'
Let's run it in the usual way:
$ ansible-playbook -i test01.fale.io, variables.yaml
You should see the following result:
PLAY [all] **********************************************************
TASK [setup] ********************************************************
ok: [test01.fale.io]
TASK [Set variable 'name'] ******************************************
ok: [test01.fale.io]
TASK [Print variable 'name'] ****************************************
ok: [test01.fale.io] => {
"msg": "Test machine"
}
PLAY RECAP **********************************************************
test01.fale.io : ok=3 changed=0 unreachable=0 failed=0
If we analyze the code we have just executed, it should be pretty clear what's going on. We set a variable (that in Ansible are called facts) and then we print it with the debug function.
Tip
Variables should always be between quotes when you use this expanded version of YAML.
Ansible allows you to set your variables in many different ways, that is, either by passing a variable file, declaring it in a playbook, passing it to the ansible-playbook command using -e / --extra-vars, or by declaring it in an inventory file (we will be discussing more in-depth about this in the next chapter).
It's now time to start using some metadata that Ansible obtained during the setup phase. Let's start by looking at the data that is gathered by Ansible. To do this, we will execute:
$ ansible all -i HOST, -m setup
In our specific case, this means executing the following:
$ ansible all -i test01.fale.io, -m setup
We can obviously do the same with a playbook, but this way is faster. Also, for the "setup" case, you will need to see the output only during the development to be sure to use the right variable name for your goal.
The output will be something like this:
test01.fale.io | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"178.62.36.208",
"10.16.0.7"
],
"ansible_all_ipv6_addresses": [
"fe80::601:e2ff:fef1:1301"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "04/25/2016",
"ansible_bios_version": "20160425",
"ansible_cmdline": {
"ro": true,
"root": "LABEL=DOROOT"
},
"ansible_date_time": {
"date": "2016-05-14",
"day": "14",
"epoch": "1463244633",
"hour": "12",
"iso8601": "2016-05-14T16:50:33Z",
"iso8601_basic": "20160514T125033231663",
"iso8601_basic_short": "20160514T125033",
"iso8601_micro": "2016-05-14T16:50:33.231770Z",
"minute": "50",
"month": "05",
"second": "33",
"time": "12:50:33",
"tz": "EDT",
"tz_offset": "-0400",
"weekday": "Saturday",
"weekday_number": "6",
"weeknumber": "19",
"year": "2016"
},
"ansible_default_ipv4": {
"address": "178.62.36.208",
"alias": "eth0",
"broadcast": "178.62.63.255",
"gateway": "178.62.0.1",
"interface": "eth0",
"macaddress": "04:01:e2:f1:13:01",
"mtu": 1500,
"netmask": "255.255.192.0",
"network": "178.62.0.0",
"type": "ether"
},
"ansible_default_ipv6": {},
"ansible_devices": {
"vda": {
"holders": [],
"host": "",
"model": null,
"partitions": {
"vda1": {
"sectors": "41943040",
"sectorsize": 512,
"size": "20.00 GB",
"start": "2048"
}
},
"removable": "0",
"rotational": "1",
"scheduler_mode": "",
"sectors": "41947136",
"sectorsize": "512",
"size": "20.00 GB",
"support_discard": "0",
"vendor": "0x1af4"
}
},
"ansible_distribution": "CentOS",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.2.1511",
"ansible_dns": {
"nameservers": [
"8.8.8.8",
"8.8.4.4"
]
},
"ansible_domain": "",
"ansible_env": {
"HOME": "/home/fale",
"LANG": "en_US.utf8",
"LC_ALL": "en_US.utf8",
"LC_MESSAGES": "en_US.utf8",
"LESSOPEN": "||/usr/bin/lesspipe.sh %s",
"LOGNAME": "fale",
"MAIL": "/var/mail/fale",
"PATH": "/usr/local/bin:/usr/bin",
"PWD": "/home/fale",
"SHELL": "/bin/bash",
"SHLVL": "2",
"SSH_CLIENT": "86.187.141.39 37764 22",
"SSH_CONNECTION": "86.187.141.39 37764 178.62.36.208 22",
"SSH_TTY": "/dev/pts/0",
"TERM": "rxvt-unicode-256color",
"USER": "fale",
"XDG_RUNTIME_DIR": "/run/user/1000",
"XDG_SESSION_ID": "180",
"_": "/usr/bin/python"
},
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "178.62.36.208",
"broadcast": "178.62.63.255",
"netmask": "255.255.192.0",
"network": "178.62.0.0"
},
"ipv4_secondaries": [
{
"address": "10.16.0.7",
"broadcast": "10.16.255.255",
"netmask": "255.255.0.0",
"network": "10.16.0.0"
}
],
"ipv6": [
{
"address": "fe80::601:e2ff:fef1:1301",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "04:01:e2:f1:13:01",
"module": "virtio_net",
"mtu": 1500,
"pciid": "virtio0",
"promisc": false,
"type": "ether"
},
"ansible_eth1": {
"active": false,
"device": "eth1",
"macaddress": "04:01:e2:f1:13:02",
"module": "virtio_net",
"mtu": 1500,
"pciid": "virtio1",
"promisc": false,
"type": "ether"
},
"ansible_fips": false,
"ansible_form_factor": "Other",
"ansible_fqdn": "test",
"ansible_hostname": "test",
"ansible_interfaces": [
"lo",
"eth1",
"eth0"
],
"ansible_kernel": "3.10.0-327.10.1.el7.x86_64",
"ansible_lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"broadcast": "host",
"netmask": "255.0.0.0",
"network": "127.0.0.0"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 65536,
"promisc": false,
"type": "loopback"
},
"ansible_machine": "x86_64",
"ansible_machine_id": "fd8cf26e06e411e4a9d004010897bd01",
"ansible_memfree_mb": 6,
"ansible_memory_mb": {
"nocache": {
"free": 381,
"used": 108
},
"real": {
"free": 6,
"total": 489,
"used": 483
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"ansible_memtotal_mb": 489,
"ansible_mounts": [
{
"device": "/dev/vda1",
"fstype": "ext4",
"mount": "/",
"options": "rw,relatime,data=ordered",
"size_available": 18368385024,
"size_total": 21004894208,
"uuid": "c5845b43-fe98-499a-bf31-4eccae14261b"
}
],
"ansible_nodename": "test",
"ansible_os_family": "RedHat",
"ansible_pkg_mgr": "yum",
"ansible_processor": [
"GenuineIntel",
"Intel(R) Xeon(R) CPU E5-2630L v2 @ 2.40GHz"
],
"ansible_processor_cores": 1,
"ansible_processor_count": 1,
"ansible_processor_threads_per_core": 1,
"ansible_processor_vcpus": 1,
"ansible_product_name": "Droplet",
"ansible_product_serial": "NA",
"ansible_product_uuid": "NA",
"ansible_product_version": "20160415",
"ansible_python_version": "2.7.5",
"ansible_selinux": {
"status": "disabled"
},
"ansible_service_mgr": "systemd",
"ansible_ssh_host_key_dsa_public": "AAAAB3NzaC1kc3MAAACBAPEf4dzeET6ukHemTASsamoRLxo2R8iHg5J1bYQUyuggtRKlbRrHMtpQ8qN5CQNtp8J+2Hq6/JKiDF+cdxgOehf9b7F4araVvJxqx967RvLNBrMWXv7/4hi+efgXG9eejGoGQNAD66up/fkLMd0L8fwSwmTJoZXwOxFwcbnxCZsFAAAAFQDgK7fka+1AKjYZNFIfCB2b0ZitGQAAAIADeofiC5q+SLgEvkBCUCTyJ+EVb6WHeHbVdrpE2GdnUr03R6MmmYhYZMijruS/rcpzBLmi8juDkqAWy6Xqxd+DwixykntXPeUFS3F7LK5vNwFalaRltPwr4Azh+EeSUQ2Zz2AdKx6zSqtLOD8ZMPkRDvz4WGHGmeR+i7UFsFDZdgAAAIEAy26Tx0jAlY3mEaTW9lQ9DoGXgPBxsSX/XqeLh5wBaBO6AJaIrs0dQJdNeHcMhFy0seVkOMN1SpeoBTJSoTOx15HAGsKsAcmnA5mcJeUZqptVR6JxROztHw3zQePQ3/V3KQzAN31tIm3PbKztlEZbXRUM7RV5WsdRHTb8rutENhY=",
"ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPDXQ9rjgDmUKsEWH4U2vg4iqtK+75urlj9nwW+rNNTFHTE5oG82sOlO6o0tUY8LXgB/tJnIcJ1hINdrWrZNpn4=",
"ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCwQx5EElH7FeD/agB/gCJfBUEVhk44tldzdEzwc2IEbI59relTGNOU7soCCMcSH7nwlEbOOvmLa2R/YaXdHv/cb1aXBC/wj/m4ZHylBeF5qzECUkeaB3+CT+hp8qHHApclFr2lm2CwZ+YXjEyjJ3en4K3gLlIQyQjgE2F57kmD1FVVDSJFvNTn+NQvb3DPppND+HKEeHwrJ0GgznoP62yobEgriAIBSGf//0WHCO/9shEvauoRpPM+U9pU7lv637s7qyubIqyrs5fz3u34qBj8oCATOefRN1wsfJDeMG0D5ryI6BI6t/eAi8BPr7VHJSQBk+buM9Jr1yoMQTEasq2J",
"ansible_swapfree_mb": 0,
"ansible_swaptotal_mb": 0,
"ansible_system": "Linux",
"ansible_system_vendor": "DigitalOcean",
"ansible_uptime_seconds": 603067,
"ansible_user_dir": "/home/fale",
"ansible_user_gecos": "",
"ansible_user_gid": 1000,
"ansible_user_id": "fale",
"ansible_user_shell": "/bin/bash",
"ansible_user_uid": 1000,
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "host",
"ansible_virtualization_type": "kvm",
"module_setup": true
},
"changed": false
}
As you can see, from this huge list of options, you can gain a huge quantity of information, and you can use them as any other variable. Let's print the OS name and the version. To do so, we can create a new playbook called setup_variables.yaml with the following content:
---
- hosts: all
remote_user: fale
tasks:
- name: Print OS and version
debug:
msg: '{{ ansible_distribution }} {{ ansible_distribution_version }}'
Run it with the following:
$ ansible-playbook -itest01.fale.io, setup_variables.yaml
This will give us the following output:
PLAY [all] *******************************************************
TASK [setup] *****************************************************
ok: [test01.fale.io]
TASK [Print OS and version] **************************************
ok: [test01.fale.io] => {
"msg": "CentOS 7.2.1511"
}
PLAY RECAP *******************************************************
test01.fale.io : ok=2 changed=0 unreachable=0 failed=0
As you can see, it printed the OS name and version, as expected. In addition to the methods seen previously, it's also possible to pass a variable using a command-line argument. In fact, if we look in the Ansible help, we will notice the following:
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON
The same lines are present in the ansible-playbook command as well. Let's make a small playbook called cli_variables.yaml with the following content:
---
- hosts: all
remote_user: fale
tasks:
- name: Print variable 'name'
debug:
msg: '{{ name }}'
Execute it with the following:
$ ansible-playbook -i test01.fale.io, cli_variables.yaml -e 'name=test01'
We will receive the following:
PLAY [all] *******************************************************
TASK [setup] *****************************************************
ok: [test01.fale.io]
TASK [Print variable 'name'] *************************************
ok: [test01.fale.io] => {
"msg": "test01"
}
PLAY RECAP *******************************************************
test01.fale.io : ok=2 changed=0 unreachable=0 failed=0
In case we forgot to add the additional parameter to specify the variable, we would have executed it as:
$ ansible-playbook -i test01.fale.io, cli_variables.yaml
We would have received the following output:
PLAY [all] *******************************************************
TASK [setup] *****************************************************
ok: [test01.fale.io]
TASK [Print variable 'name'] *************************************
fatal: [test01.fale.io]: FAILED! => {"failed": true, "msg": "'name' is undefined"}
NO MORE HOSTS LEFT ***********************************************
to retry, use: --limit @cli_variables.retry
PLAY RECAP *******************************************************
test01.fale.io : ok=1 changed=0 unreachable=0 failed=1
Now that we have learned the basics of playbooks, let's create a web server from scratch using them. To do so, let's start from the beginning, creating an Ansible user and then moving forward from there.