How to retain Idempotency in Ansible while restarting HTTPD service ?
Deepak Sharma
3 x RedHat Certified Engineer (EX200, EX294, EX180) || DevOps Engineer || Docker || K8s || Ansible || Linux || Git || Github || Gitlab || Terraform || Jenkins || Cloud Computing || AWS
Objective
We create an playbook to configure apache web-server according to our requirement. So we change in configuration file .But the changes are only apply if restart httpd service. We solve this challenge in this article.
Before start , first understand some basic terms that are used here.
Introduction
1. What is Ansible?
Ansible is a software tool that provides simple but powerful automation for cross-platform computer support. It is primarily intended for IT professionals, who use it for application deployment, updates on workstations and servers, cloud provisioning, configuration management, intra-service orchestration, and nearly anything a systems administrator does on a weekly or daily basis. Ansible doesn't depend on agent software and has no additional security infrastructure, so it's easy to deploy.
2. How Ansible works
Ansible works by connecting to nodes (clients, servers, or whatever you're configuring) on a network, and then sending a small program called an Ansible module to that node. Ansible executes these modules over SSH and removes them when finished. The only requirement for this interaction is that your Ansible control node has login access to the managed nodes. SSH Keys are the most common way to provide access, but other forms of authentication are also supported.
3. What is idempotence?
In general, idempotence is “the property of certain operations in mathematics and computer science that can be applied multiple times without changing the result beyond the initial application”. For Ansible it means after 1 run of a playbook to set things to a desired state, further runs of the same playbook should result in 0 changes.
4 .Handlers
Sometimes you want a task to run only when a change is made on a machine. For example, you may want to restart a service if a task updates the configuration of that service, and not if the configuration is unchanged. Ansible uses handlers to address this use case. Handlers are tasks that only run when notified. Each handler should have a globally unique name. For triggering handler we need to use notify directive. Basically when ever any changes are made it will notify handler and hence handler's task would be executed.
Pre-requisite
For solving this challenge, you should have a configured Ansible Controller node. For this , we have to update ansible.cfg and in inventory file update managed node ip , username and password.
ansible.cfg
inventory file
We can check connectivity
ansible all -m ping
Now we have connectivity with managed node . So we are able to run our playbook.
Problem Statement
Restarting httpd Service is not idempotence in nature and also consume more resources to suggest a way to rectify this challenge in Ansible playbook. In detail, whenever HTTPD webserver’s service has to be restarted every time a change is made in its Configuration File. So considering this fact, usually we’ll give the keyword restarted under state, the demerit of following this step is that even when no changes have been made in the configuration file the service will restart every time we play the playbook. But we want the service to be restarted only when there are some changes in the configuration file… How to solve this?
Let's Started
Here we want to configure apache web-server with our custom requirement like change port no, change document root etc.
Step-1 Create Configuration file
For this first create the configuration file
vim lw.conf.j2
Listen {{ http_port }} <VirtualHost {{ ansible_default_ipv4['address'] }}:{{ http_port }}> DocumentRoot {{ document_root }} </Virtualhost>
- Here I use some pre-created variable and some user-created. I create a variable http_port to change the port of web-server. So we can directly change value of port only one location .
- I create document_root variable to change the location of webpages.
- To dynamically retrieve ip of managed node , I use pre-created ansible_default_ipv4['address'] variable and retrieve value by ansible facts. So if new managed node come , then we only need to update the inventory file .
Step-2 Create playbook
This playbook will also configure yum and then install required software.
Step-3 Run ansible-playbook
We can run ansible-playbook by
ansible-playbook web.py
Here we can see that playbook run without any error.
- Now I am going to the manage nodes and see the configuration , whatever we have did in the playbook.
- We see our uploaded configuration file
Here ansible retrieve the variable values by the ansible_facts and before uploading file to managed node, they replace with their values.
We can also see our web-page by managed node ip:port in chrome browser . Because we already add rule in firewall of managed node.
Note- If you are unable to change port no. , then it may be due to security of selinux . So disable the selinux and then try. To disable selinux in redhat-8 by "setenforce 0" command.
Thanks,