Today I am learning about working with notification. One of the biggest advantages of Ansible is its ability, compared to a bash script to notify. The 6 tools which Ansible could easily work with include
Today I am learning about working with roles. According to the author, the definition of a role is a set of playbooks, templates, files or variables used to achieve a specific goal. For example, the database role and the web server role can be cleanly separated.
Today I am learning about working with local_action feature. This feature allows us to run certain tasks locally on the machine that runs Ansible rather than logging into a remote box and running these commands.
---
- hosts: database
remote_user: vagrant
tasks:
- name: Count processes running on the remote system
shell: ps | wc -l
register: remote_processes_number
- name: Print remote running processes
debug:
msg: '{{ remote_processes_number.stdout }}'
- name: Count processes running on the local system
local_action: shell ps | wc -l
register: local_processes_number
- name: Print local running processes
debug:
msg: '{{ local_processes_number.stdout }}'
Delegating a Task
If you wish to execute an action a different system. For example, you may want to do something on a database node while working on an application node or a localhost, you can use the delegate_to: HOST Property. This is useful when there are complex procedures need to be executed by the local machine or any other machine
---
- hosts: database
remote_user: vagrant
tasks:
- name: Count processes running on the remote system
shell: ps | wc -l
register: remote_processes_number
- name: Print remote running processes
debug:
msg: '{{ remote_processes_number.stdout }}'
- name: Count processes running on the local system
shell: ps | wc -l
delegate_to: localhost
register: local_processes_number
- name: Print local running processes
debug:
msg: '{{ local_processes_number.stdout }}'
Working with Conditionals
Ansible provides conditional statements to run a task only when a specified condition(s) is met
---
- hosts: webserver
remote_user: vagrant
tasks:
- name: Print the ansible_os_family value
debug:
msg: '{{ ansible_os_family }}'
- name: Ensure the httpd package is updated
yum:
name: httpd
state: latest
become: True
when: ansible_os_family == 'RedHat'
- name: Ensure the apache2 package is updated
apt:
name: apache2
state: latest
become: True
when: ansible_os_family == 'Debian'
Boolean Conditionals
Apart from matching string, you can check whether a variable is true. Ansible provides a way to check whether a variable is defined. The below features allow us to put the Ansible playgroup in a failure state if the backup_folder is not set
---
- hosts: all
remote_user: ansible
vars:
backup: True
tasks:
- name: Check if the backup_folder is set
fail:
msg: 'The backup_folder needs to be set'
when: backup_folder is not defined
- name: Copy the crontab in tmp if the backup variable is true
copy:
src: /etc/crontab
dest: '{{ backup_folder }}/crontab'
remote_src: True
when: backup
Working with Handlers
Every handler will run at the end of the playbook if notified. Ansible will make sure, how many times you notify the service, it will call that task once after all other tasks has completed.
---
- hosts: webserver
remote_user: vagrant
tasks:
- name: Ensure the HTTPd package is installed
yum:
name: httpd
state: present
become: True
- name: Ensure the HTTPd service is enabled and running
service:
name: httpd
state: started
enabled: True
become: True
- name: Ensure HTTP can pass the firewall
firewalld:
service: http
state: enabled
permanent: True
immediate: True
become: True
- name: Ensure HTTPd configuration is updated
copy:
src: website.conf
dest: /etc/httpd/conf.d
become: True
notify: Restart HTTPd
handlers:
- name: Restart HTTPd
service:
name: httpd
state: restarted
become: True
Today I am learning on working with Inventory Files. This time we are dealing with multiple hosts. These hosts have to be placed in the inventory file. An example is pasted here. In hosts.ini, we have
firstrun.yaml is taken from the site listed. It is to ensure the ansible user exist, accept the SSH keys and provided with sudoers rights with no password.
hosts: all
user: vagrant
tasks:
- name: Ensure ansible user exists
user:
name: ansible
state: present
comment: Ansible
become: True
- name: Ensure ansible user accepts the SSH key
authorized_key:
user: ansible
key: https://github.com/fale.keys
state: present
become: True
- name: Ensure the ansible user is sudoer with no password required
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^ansible ALL\='
line: 'ansible ALL=(ALL) NOPASSWD:ALL'
validate: 'visudo -cf %s'
become: True
Regular Expressions
If you have a larger number of servers with predictable names, you may want to consider the following expression. You can save 100 lines of listing the server with the following expression
If you wish to set a variable for the whole group, you may want to set a variable that is valid for the whole group,. A quick note from the book is that the host variables will override the group variables if the same variable is declared in both spaces.
If you want to perform an action on every file present in a certain folder like copying multiples files with similar names from one folder to another, you can do the following
---
- hosts: all
remote_user: ansible
tasks:
- name: Ensure the folder /tmp/iproute2 is present
file:
dest: '/tmp/iproute2'
state: directory
become: True
- name: Copy files that start with rt to the tmp folder
copy:
src: '{{ item }}'
dest: '/tmp/iproute2'
remote_src: True
become: True
with_fileglob:
- '/etc/iproute2/rt_*'
Checking whether the root partition has run out of inodes. Use the command. If it shows 100%, there are many small files. Perhaps, do look for some of these files at /tmp
-h argument produces the human-readable output -x restricts the search to the current directory -d 1 is the summary for each directory sort -h produces human-readable output and the directories with the largest usage will appear at the bottom of the list.
---
- hosts: all
remote_user: ansible
tasks:
- name: Ensure NTP is installed
yum:
name: ntp
state: present
become: True
- name: Ensure the timezone is set to UTC
file:
src: /usr/share/zoneinfo/GMT
dest: /etc/localtime
state: link
become: True
- name: Ensure the NTP service is running and enabled
service:
name: ntpd
state: started
enabled: True
become: True
The first set of codes deal with the installation and enabling of HTTPd package and services. In addition, both HTTP and HTPS must be able to pass through the firewalld
--
- hosts: all
remote_user: ansible
tasks:
- name: Ensure the HTTPd package is installed
yum:
name: httpd
state: present
become: True
- name: Ensure the HTTPd service is enabled and running
service:
name: httpd
state: started
enabled: True
become: True
- name: Ensure HTTP can pass the firewall
firewalld:
service: http
state: enabled
permanent: True
immediate: True
become: True
- name: Ensure HTTPS can pass the firewall
firewalld:
service: https
state: enabled
permanent: True
immediate: True
become: True
Reviewing and Running the Deployment, we can use the command to fire it.
Assuming the Website is a simple single-page website using a simple template call index.html.j2
---
- hosts: all
remote_user: ansible
tasks:
- name: Ensure the website is present and updated
template:
src: index.html.j2
dest: /var/www/html/index.html
owner: root
group: root
mode: 0644
become: True
Just a note that the “become: True” parameter represents the fact that the tasks should be executed with sudo access. In other words, the sudo user’s file should allow access
I have been learning from this book Fabio Alessandro Locati, published under Packt>
I thought I just capture a few learning notes as I read.
Introduction to Playbooks
Playgroups are one of the core features of Ansible and tell what Ansible what to execute. They are like a do-list for Ansible that contains a list of tasks; each task internally links to a piece of code called a module
- hosts: all
remote_user: vagrant
tasks:
- name: Ensure the HTTPd package is installed
yum:
name: httpd
state: present
become: True
- name: Ensure the HTTPd service is enabled and running
service:
name: httpd
state: started
enabled: True
become: True
What it means?
hosts: List the Host or Host groups. The Host field is required. The –list-hosts-host will let us know which hosts the playbook is using.
remote_user: The user Ansible will be using while logging onto the system.
There are 2 tasks.
The first one is to ensure that the httpd package is present
The 2nd one is to enable the httpd service is enabled and running
The tasks are quite self-explanatory.
become: True. The commands should be executed with sudo access. If the sudo user’s file does not allow the user to run the particular command, the command will fail
Running a Playbook
$ ansible-playbook -i host setup_apache.yml
Ansible Verbosity
You can increase the verbosity by using the parameter -v, -vv or -vvv
Variables in Ansible
---
- hosts: all
remote_user: vagrant
tasks:
- name: Print OS and version
debug:
msg: '{{ ansible_distribution }} {{ ansible_distribution_version }}'
Creating the Ansible User
---
- hosts: all
user: vagrant
tasks:
- name: Ensure ansible user exists
user:
name: ansible
state: present
comment: Ansible
become: True
- name: Ensure ansible user accepts the SSH key
authorized_key:
user: ansible
key: https://github.com/fale.keys
state: present
become: True
- name: Ensure the ansible user is sudoer with no password required
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^ansible ALL\='
line: 'ansible ALL=(ALL) NOPASSWD:ALL'
validate: 'visudo -cf %s'
become: True
The lineinfile is an interesting module. It works in a similar way to sed (a stream editor) where you specify the regular expression that will be used to match the line, and then specify the new line that will be used to substitute the matched line.