Full disclosure: I’m a casual user of Ansible, Python and Bash. I’m not an expert on any of them. The notes below are my personal impression after playing around with Ansible for a few months, mostly to run ScyllaDB and Cassandra clusters on EC2.
Why I love Ansible:
Ansible is straightforward to use, no batteries (or local agent) required. When I have a herd of ScyllaDB servers, I can stop the service on all of them just by running
ansible -i my.ini ScyllaDB -u centos --sudo -m service -a "name=scylla-server state=stopped"
Ansible is declarative, you state the end state, not the actions.
Want to update a row in scylla.yaml? Use the lineinfile module.
ansible -i my.ini ScyllaDB -u centos --sudo -m lineinfile -a 'dest=/etc/scylla/scylla.yaml regexp="auto_bootstrap: false" line="# auto_bootstrap: false"'
Use nodetool to refresh tables.
ansible -i my.ini ScyllaDB -u centos -m shell -a 'nodetool refresh keyspace1 standard1'
Even better, when running on Amazon EC2, I can use EC2 dynamic inventory to allow me to do the same without even managing my local server list (my.ini above).
Next natural step is to group tasks into to playbooks, and then organized them into roles. Each role is responsible for a task such as installing Java or installing ScyllaDB. For example, in my ScyllaDB/Cassandra project, I created roles for Cassandra and ScyllaDB configuration. Roles are to Ansible what functions are in a programming language—building blocks to combine.
Automation, with no batteries required
Big ecosystem of module and extensions. I already mentioned the EC2 module, and I use the service and lineinfile modules above. There are many more, to do anything from removing and adding packages, to manipulate directories, to what not.
What I hate (really just dislike) about Ansible
Let’s say I want to remove a directory as part of a playbook. Easy, I will use the file module:
- file: path=/data state=absent
Missing a module? Just write your own in python What’s not to like? Well, I already have a way to remove directories in Unix, rmdir, and a way to remove directories in Python, os.rmdir. Ansible introduce a new layer of abstraction one need to learn for every single command, from ls, to mkdir to yum. Here are two more examples:
Set operations and varibales
As part of my stress playbook I extracted IP addresses of servers in the intersection of groups DB and aRegion. Again, the Ansible solution is pretty slick:
- debug: msg="" with_items: groups.DB | intersect (groups.aRegion) register: output
The intersect command comes from Jinja2 filter, one more DSL to learn when using Ansible, and register is the way to store values in variables.
Ansible has loops and even nested loops. Here is a simplified example from the same project, waiting for all servers to open SSH port:
- name: Wait for SSH to come up wait_for: host= port=22 delay=60 timeout=320 state=started with_subelements: - ec2_load.results - instances
In all of these examples, and there are more, Ansible provide a reasonable solution which is very different from what Python or Bash provides. On some cases better, on other, like flow control, worse.
Can we do better?
It is very common for a DSL to be so useful, that people will stretch it beyond its original goals (ant, XSD, many more). Is it possible to have the Ansible functionality as a Python internal DSL? Can we use Python control flow, while keeping the high level, declarative abstraction of Ansible? Someone smarter than me will need to answer these questions. In the meantime I will keep using Ansible. Now that I’m ⅔ up the learning curve, I’m too afraid to climb down.