It seems likely you are coming at this from the perspective of "when I find an ansible playbook on github its hard to follow whats going on".
There is a certain truth to that, but much of its complexity is probably related to said playbook developers trying to abstract away specifics and create a playbook that works on a variety of distributions / configuration options.
Ansible can be as simple as a single file that proceeds sequentially like a bash script.
Most of the ansible roles I come across written by my team are not idempotent either, its a huge lie that Ansible is idempotent. Its idempotent if you put the effort into make it be but if I see tons of shell or command module invocations without prerequisite checks to see if the work should be done. Most devs I see using Ansible treat it like a shell script written in YAML and to that purpose it sucks.
I can appreciate that I learned the term idompotency from working with Ansible, but I think they failed to really make it a feature of the language- it could have been a stronger default, explicit, like Unsafe in Rust. As it stands, writing idempotent Ansible takes as much discipline and intentionality as any other language, and can prevent integrating roles that other's have written without such discipline. There is value in it, but not in respect to idempotentcy as any sort of inherent principal (at least outside of the std lib, which is ofc pretty great abt it).
This. The built in tasks only get you so far. If you have anything custom you have to create the task for it yourself, with idempotency in mind, at which point you might as well have the exact same logic in a ./install.py file.
Even with the standard library of predefined task, most devs don't put in the effort to learn them since "ifconfig | grep" and other commands are baked into their muscle memory, they would rather make a quick and dirty bash-step than figure out what is the best practice ansible-equivalent. In the end the result is a sequential shell script written in yaml with no guard rails keeping it idempotent, plus riddled with jinja template-substitutions making it a nightmare to follow.
A truly declarative system would be designed more like makefiles, really enforcing idempotence. With steps in playbooks being executed in sequence it's too easy to fall back to script-thinking and side-effects. Sadly i'm not aware of any.
There is nothing magical about Ansible that makes it idempotent by default either.
The simple stuff like having specific versions of a package installed that you might be thinking of is just using Python under the hood. If you get into more complicated stuff, especially around custom infrastructure abstractions you use internally, guess what, you will have to write a bunch of Python and effectively call it from Ansible. And you will have to put in extra effort to make sure it's idempotent.
At which point you start thinking...why not just write a Python script instead? At least that gives you all of the flexibility.
> It seems likely you are coming at this from the perspective of "when I find an ansible playbook on github its hard to follow whats going on".
No, I've worked with ansible over 3 jobs, for the past 4 years. It hasn't been hard to convince colleagues to move away from Ansible once I show the competition. Sadly the migration process is rarely easy.
Yes, it can get hairy but I just have a hard time seeing an adhoc mess of python and bash doing the equivalent amount of lifting without becoming an even bigger hairball. And the thing is, you can also just run those same bash and python scripts using Ansible if you really want to, just to keep them orchestrated properly.
What about it isn't idempotent for you? Are you falling into the anti-pattern of using shell/command all over the place instead of real modules?
We have playbooks installing and managing our databases, web servers, VoIP PBX, DNS servers, backend services, and on and on. All completely idempotent and safe to run at any time against any host. No special effort whatsoever was required to make that safe to do.
Perhaps I'm not using it for its intended use case, but I've run into many issues where built-ins simply don't do the job. I'm using it for setting up my local personal machines, including a remarkable tablet.
Neither of those of idempotent.
It seems likely you are coming at this from the perspective of "when I find an ansible playbook on github its hard to follow whats going on".
There is a certain truth to that, but much of its complexity is probably related to said playbook developers trying to abstract away specifics and create a playbook that works on a variety of distributions / configuration options.
Ansible can be as simple as a single file that proceeds sequentially like a bash script.