Is Ansible declarative or imperative?

There is a lot of discussion about this topic. And the question implies that it is either one or the other. I think that is the wrong question. This Blog post will describe why.

Writing something like that is declarative for sure.

- name: Webservers 
     - apache2
     - nginx	
    state: present

But we could get the same result with that task as well.

- name: Install Webservers 
  shell: apt-get install "{{item}}"
    - apache2
    - nginx

The latter is the one that seems natural to a sysadmin who starts using Config Management. So it is not uncommon that we find those things in playbooks. And sometimes it gets even more complicated:

- name: Check if Apache is installed
  shell: dpkg -l apache2
  register: apache_installed 
- name: Install Apache
  shell: apt-get install apache2
  when: apache_installed.rc !=0

- name: Check if Nginx is installed
  shell: dpkg -l nginx
  register: nginx_installed 
- name: Install Nginx
  shell: apt-get install nginx 
  when: nginx_installed.rc !=0

A simple apt-get install apache2 nginx in a bash script (imperative approach) would do the same job. We are not forced to make things more complicated than they have to be. Ansible (as most other config management tools) allows us to use declarative and imperative methods. But it is not Ansible itself that is declarative or imperative. It is how we use it.

There is nothing wrong with using loops and conditions occasionally. But if more than 50% of our tasks have a when condition attached there is probably a better way. We can not solve everything with declarative code. Sometimes we need more flexibility. Instead of creating complicated contructs and flow control in Ansible we can write a simple bash script that does the same job. We can still call that from an Ansible task.

“Simlicity is the ultimate sophistication” - Leonardo da Vinci