Going fordward with Ansible
Variables
The last post shown how a playbook was able to install and configure an Apache server and also to open needed ports on the firewall. If we wanted to install a FTP server we should create a new playbook or duplicate a task, but thanks to variables we are going to see how to reuse the same task on the same playbook.
This is the original playbook:
$ cat playbooks/prepare-WebServers.yaml --- - name: Install and configure webservers services hosts: webservers remote_user: centos become: True tasks: - block: - name: Install Apache package yum: name: httpd state: installed - name: Install Firewalld package yum: name: firewalld state: installed - block: - name: Start and enable Apache service service: name: httpd enabled: true state: started - name: Start and enable Firewalld service service: name: firewalld enabled: true state: started - block: - name: Enable firewall rules for Apache firewalld: state: enabled service: http permanent: true immediate: true - block: - name: create index file shell: echo 'Hello World!' > /var/www/html/index.html ...
VARIABLES
Thanks to variables usage we can set some values outside the playbook. e.g. it is possible to install NGING instead of Apache web server.
The variables can be defined through different levels, shown from lower to higher precedence order. NODE: there are more levels, but here are most usual.
- inventory_dir/group_vars/all
- playbook_dir/group_vars/all
- inventory_dir/group_vars/*
- playbook_dir/group_vars/*
- inventory_dir/host_vars/*
- playbook_dir/host_vars/*
- play vars
- play vars_files
- role vars
- block vars
- task vars
- include_vars
- extra vars (option –extra-vars|-e in command line)
GROUP_VARS and HOST_VARS
The group_vars and host_vars, defined at inventory or playbook level, allow to define a set of variables to use on hosts or hosts groups. Ansible sets as a good practice:
A lot of folks may ask about how variables override another. Ultimately it’s Ansible’s philosophy that it’s better you know where to put a variable, and then you have to think about it a lot less.
Avoid defining the variable “x” in 47 places and then ask the question “which x gets used”. Why? Because that’s not Ansible’s Zen philosophy of doing things.
There is only one Empire State Building. One Mona Lisa, etc. Figure out where to define a variable, and don’t make it complicated.
So lets configure our webserver package in a variable to be able to change their value without modify the playbook.
$ cat playbooks/group_vars/webservers.yaml --- packages: nginx services: http ... $ cat playbooks/prepare-WebServers.yaml --- - name: Install and configure webservers services hosts: webservers remote_user: centos become: True tasks: - block: - name: Install WebServer package yum: name: "{{ package }}" state: installed - name: Install Firewalld package yum: name: firewalld state: installed - block: - name: Start and enable Apache service service: name: "{{ services }}" enabled: true state: started - name: Start and enable Firewalld service service: name: firewalld enabled: true state: started - block: - name: Enable firewall rules for Apache firewalld: state: enabled service: http permanent: true immediate: true - block: - name: create index file shell: echo 'Hello World!' > /var/www/html/index.html ...
Basic loops
Another feature we can find on the Ansible playbooks is the loops, that allow us to run a task n times with different values. For that we will use the keyword with_items that will receive a list to loop over, and will generate a variable called item, with a task scope that will have the value of the loop.
In the next example I will take the install packages task and I will do a loop with the packages httpd and firewalld. Because of this we avoid to repeat a task, making easier to read and configure the playbook.
- name: Install packages yum: name: "{{ item }}" state: installed with_items: - httpd - firewalld
You can also pass the variables as elements on the loop:
$ cat playbooks/group_vars/webservers --- packages: - httpd - firewalld ... $ cat playbooks/prepare-WebServers.yaml - name: Install packages yum: name: "{{ item }}" state: installed with_items: - "{{ packages }}"
Registering variables
Ansible allows to register the return values from a task, so we can work with them on another task. Depending the ansible module used, the variable will contain different types. The keyword is register
Lets take a look and later analyze the next example.
$ cat playbooks/test-Register.yaml tasks: - block: - name: Register date command: date register: date_registered - block: - name: Check debug: var: date_registered
The result will be:
ok: [localhost] => {
"date_registered": {
"changed": true,
"cmd": [
"date"
],
"delta": "0:00:00.106724",
"end": "2017-04-07 08:03:11.264052",
"rc": 0,
"start": "2017-04-07 08:03:11.157328",
"stderr": "",
"stdout": "Fri Apr 7 08:03:11 UTC 2017",
"stdout_lines": [
"Fri Apr 7 08:03:11 UTC 2017"
],
"warnings": []
}
}
If you take a look to the result, you can use the values in another tasks, as these are defined as elements inside an object.
A simple example would be to show the system date, so I will use the stdout_lines element from the date_registered object.
$ cat playbooks/test-Register.yaml tasks: - block: - name: Register date command: date register: date_registered - block: - name: Check debug: var: date_registered.stdout_lines
Conditions
We can not only use variables as parameter form some elements in the tasks but we also can use the variables to conditionally run another tasks. The keyword is when
As example we can define a task that creates the index.html file only if the package httpd is installed.
$ cat playbooks/group_vars/webservers --- packages: - httpd - firewalld ... $ cat playbooks/prepare-WebServers.yaml - name: Create index.html if httpd is in packages copy: dest: /var/www/html/index.html force: no content: | <html> <body> <h1>Hello World!</h1> </body> </html> with_items: "{{ packages }}" when: item == 'httpd'
Up to this point. I think that to be Volume 2 of this tutorial, I have advanced a lot. See you!!