Any person somewhat familiar with Python can probably tell what this
does. In Ansible, you'll need to first [run the command](https://docs.ansible.com/ansible/latest/plugins/shell.html) and have a
second task to [parse the result](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html#formatting-data-yaml-and-json), both of which involves slow
round-trips with the server:
- name: gather information about disk
shell: "qemu-img info --output=json {{disk_path}}"
register: result
- name: parse disk information as JSON
set_fact:
disk_info: "{{ result.stdout | from_json }}"
That is much more verbose and harder to discover unless you're already
deeply familiar with Ansible's processes and data structures.
Compared with Puppet, Ansible's "collections" look pretty chaotic. The
[official collections index](https://docs.ansible.com/ansible/latest/collections/) is weirdly disparate and incomplete
while [Ansible Galaxy](https://galaxy.ansible.com/) is a wild jungle.
For example, there are [677 different Prometheus collections](https://galaxy.ansible.com/search?deprecated=false&keywords=prometheus&order_by=-relevance&page=1) at
the time of writing. The most popular Prometheus collection one has
[lots of issues](https://github.com/prometheus-community/ansible/issues), namely:
* no support for installation through Debian packages (but you can
"skip installation")
* even if you do, incompatible service names for exporters
(e.g. `blackbox-exporter`), arguably a common problem that was also
plaguing the Puppet module until @anarcat worked on it
* the module's documentation is kind of hidden inside the source
code, for example [here is the source docs](https://github.com/prometheus-community/ansible/tree/main/roles/prometheus) which show use cases
and actual configurations, compared to the [actual role docs](https://prometheus-community.github.io/ansible/branch/main/prometheus_role.html),
which just lists supported variables
Another example is the [nginx collection](https://github.com/nginxinc/ansible-role-nginx). In general, collections
are pretty confusing coming from Puppet, where everything is united
under a "module". A Collection is actually closer to a module than a
role is, but collections and roles are sometimes, as is the case for
nginx, split in separate git repositories, which can be confusing (see
the [nginx role](https://github.com/nginxinc/ansible-role-nginx).
Taking a look at the language in general, Ansible's variable are all
globals, which means they all get "scoped" by using a prefix
(e.g. `prometheus_alert_rules`).
Documentation is sparse and confusing. For example, I eventually
figured out how to pull data from a host using a `lookup` function,
but that wasn't because of the [lookup documentation](https://docs.ansible.com/ansible/latest/plugins/lookup.html) or the [pipe
plugin documentation](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pipe_lookup.html), neither of which show this simple example:
For a first time user, the distinction between a `lookup()` function
and a `shell` task is really not obvious, and the documentation
doesn't make it exactly clear that the former runs on the "client" and
the latter runs on the "server" (although even the latter can be
fuzzy, through [delegation](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html)).
And since this is becoming a "Ansible crash course for Puppet
developers", might as well add a few key references:
* the [working with playbooks](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks.html) section is possibly the most
important and useful part of the Ansible documentation
* that includes [variables](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html) and [filters](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html), critical and powerful functions that
allow processing data from variables, files, etc
*[tags](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_tags.html) can be used to run a subset of a playbook but also skip
certain parts
In the end, the main reason we use Fabric instead of Ansible is that
we use Puppet for high-level configuration management, and Ansible
conflicts with that problem space, leading to higher cognitive
load. It's also easier to just program custom processes in Python than
in Ansible. So far, however, Fabric has effectively been creating more
[legacy code](https://en.wikipedia.org/wiki/Legacy_system#Perspectives_on_legacy_code) as it has been proven hard to effectively unit test
unless a lot of care is given to keeping functions small and locally