Ansible Alternatives in Python
blog.rfox.eu
blog.rfox.eu
I use Ansible with zero issues daily as do many in our team. It’s perplexing coders fined it difficult or hard to use to the point where something as useful as Ansible becomes undesirable because it uses YAML?
I hate to say it, but the “alternatives” are just the least good somewhat similar products.
If they're going to do that, the configuration files should just use a actual programming language. Just make them actual python files (or ruby files, or whatever).
From the famous quote:
> Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
The problem here isn't that they're using lisp (or python, or yaml, or whatever), it's that they're re-implementing a very mature language with lots of supporting infrastruture poorly with lots of bugs and corner cases, rather then just using the relevant (open source) programming language itself.
I don't recall how ansible extends yaml, but Microsoft does something that sounds similar with their JSON-based ARM templates (which are for deploying cloud resources), adding functions for loops, parameters and variables. The result is predictably horrible. There are however at least APIs available for C# and others, so it's not the only automation option.
You use yaml to write code to some hidden programming language that doesn’t have any kind of formalized syntax.
Want to add a value to a parameter in your function call? Since there is no specification your IDE can’t help you look up parameter or function names.
Want to do a for-loop? Maybe some functions will support looping and other won’t, because looping is just a ` - loop-while: “a = b”` (or maybe it is double equal signs, who knows, because there is no actual IDE support.
Some example sources of discomfort:
- The context-dependent need to quote Jinja2 syntax interpolation ({{ ... }}) in some places but not others, due to conflict with YAML syntax rules.
- Undifferentiated mixing of Python evaluation (eg. list concatenation with +) and Jinja2 filtering/transformtion (eg. `| zip` and `| list`) in a single value.
- Awkward encoding of imperative programming patterns using YAML keys (eg. `loop` and `loop_control` to describe a loop; `when` to describe a conditional).
- Context-specific embedding of Python expressions (eg. raw Python code being passed as a string in the `when` property, but elsewhere being interpolated in Jinja2 interpolation).
- Implicit/magical variable naming conventions (eg. use of loop implies the existence of an `item` variable).
- No obvious scoping rules eg. variables magically available with no obvious source (they are defined in another file, or defined in a prior task).
That's from an example I wrote up over on my dotfiles repo: https://github.com/wincent/wincent/tree/master/fig#on-ansibl... - I used Ansible happily enough for years there, but concluded that at least on a little toy project like that it was more fun/pleasant/simpler to just embody the imperative, procedural work in an actual programming language. I still use Ansible in other places, to manage remote hosts, but I can't shake off the discomfort I feel about how it uses YAML.
Don't @ me with BS about putting logic in templates - I know what I'm doing.
It's not "injected" into the YAML.m
I get people have criticisms; But it's not like these things are very difficult to overcome. Outside of creating a DSL, what could actually be different?
It sounds like your complaints are more to do with Jinja + YAML and Ansible was unfortunately a victim of some of those issues?
While a lot of negatives are pointed out about the marriage between the two, there are still at least some positives I believe.
Disclaimer: I have nothing to do with the tool outside of using it.
And you ended up with some sort of half baked thing that was like a language but not. I get the same spidey sense when you look at how ansible uses YAML.
Ultimately I really do not care but it was a bad choice. I make bad choices all the time. I would expect the people who wrote Ansible do also.
We are actually seriously considering a shift to salt atm...
https://docs.saltstack.com/en/latest/ref/modules/all/salt.mo...
You can reuse all the playbooks and start scaling with salt.
https://docs.ansible.com/ansible/latest/cli/ansible-pull.htm...
so at this point both ansible and salt can go both directions, and i do infact myself make use of that. i use pull/minions on all servers in our network, and push to those servers outside our network, because they can't reach the master behind the firewall.
although zerotier has helped solve that problem, so i'll probably be able to stop using salt-ssh soon
i read that as: by the time ylu outgrow ansible, salt doesn't make sense either. but the next sentence seems to suggests to switch to salt when you outgrow ansible.
i always assumed that ansible and salt solve the same problems and when you outgrow one, you'd outgrow the other too.
Templated YAML really isn't pretty to work with.
E.g. seznam.cz (a Czech search engine) migrated from Salt to Ansible, they seem to cope ok. (There is a PDF from the LinuxDays talk last year.) Google Docs can translate PDFs even from Czech into English: https://pretalx.linuxdays.cz/media/Ansible.pdf
Some personal perspectives:
I have used Ansible in the past and didn't like it.
I have used Fabric and Fabtools many years ago (Fabtools happens to be written by a friend) and I agree that something like Fabtools is needed to make Fabric relevant. Fabric has a completely revamped version, which was quite long in the making, but not fairly stable, but AFAIK Fabric 2 doesn't (yet) have something similar to what Fabtools was to Fabric 1.
I had great hope for opsmop (https://github.com/opsmop/opsmop) by Ansible's creator, which was supposed to address Ansible's shortcomings, but he dropped the project (citing lack of traction) a few months after starting it in 2018.
At this point I'm sticking to Fabric 2, but I'm still looking for alternatives.
I'm also wondering if Augeas (https://augeas.net/ - a configuration editing tool which parses configuration files for a large set of software in their native formats and transforms them into a tree) could be used in combination with one the of tools mentioned in the post to ease the parts related to managing configuration.
I do "exporations" where I put bunch of related stuff into the wiki node and then take an evening to go over them and do some evaluation. It wasn't really meant as a comprehensive study.
I'm not sure why but it was discontinued. I would think that if anyone could make that work it would be that particular person with their previous experience from Cobbler and Ansible.
I started using Ansible when it was brand spanking new and what I've noticed over the years is that people often over complicate their Ansible use. Sometimes it's better to out source something to an RPM or a container than to use Ansible to do every single thing.
>Nobody wants to keep up with a configuration management tool, especially learn another new one (which is why creating opsmop failed), learn another YAML dialect, or maintain a full active cloud abstraction layer running on top of their cloud itself.
Ansible has it's own set of features that are largely abstracted out by it's YAML playbook syntax. You can run it across any (or almost) system, from Linux to Windows and even networking devices. You can create modules in any language you want.
For speeding up Ansible runs, a number of optimisations can be made including using Mitogen https://mitogen.networkgenomics.com/ansible_detailed.html
Alternatives listed in the blog post don't even come close to the speed and power of Ansible.
I don't understand what YAML has to do with abstraction. The example from pyinfra is pretty much the same as the ansible equivalent. Whether the feature set is comparable is a different question (I agree with you, it's probably nowhere close to ansible).
apt.packages(
{'Install iftop'},
'iftop',
sudo=True,
update=True,
)
> If you feel YAML is too complicated for youAnsible YAML is a poor substitute for a real language once you add conditional logic to the mix. Another huge downside is that composition in YAML is much harder than in any programming language. A Python (or dhall, or cue) library that compiled to ansible would be pretty swell.
Given that the average devops person is already stuck with yaml, many of those problems are addressed by jsonnet. But I agree, having it in the language would be preferable. I think it stems from the desire to make infrastructure declarative, which isn't really the case when your declarations are dynamic.
I'd like some kind of 'sensible', backwards compatible layer in Ansible that would allow me to rewrite stuff in raw Python, with 'normal' code, where it makes sense, but keep YAML for constructs that do actually look and work like lists of basic tasks.
https://opendev.org/zuul/zuul-jobs/src/branch/master/roles/t... is a nice example of some pretty complex co-install of libraries for testing under tox (and you can unit test bits of it too...).
https://zuul-ci.org/docs/zuul-jobs/ is a collection of roles and playbooks that do a lot of complicated things with nice abstractions such as this. Although they're designed to be called from the Zuul CI system, there's many good examples for anyone wanting to build out their Ansible in a scalable and maintainable way.
I said this in continuation to the line you quoted:
> You can run it across any (or almost) system, from Linux to Windows and even networking devices. You can create modules in any language you want.
This is abstracted in YAML so that anyone who uses any modules does not need to know the language it is written in. Only the YAML syntax.
And the declarative and imperative language you've built on top of that.
This is an uncharitable dismissal of a valid point. Think a bit more about the concern: is it that YAML is too hard or that it’s adding complexity in addition to that inherent to the work? You’re taking the domain-specific challenges of whatever you’re doing and adding YAML’s quirks like magic type conversion, various syntax oddities which just have to be memorized, requirement for a domain specific linter to validate things like macros, etc.; the various Ansible conventions for variable declaration and manipulation, programming language-like loops and conditionals, mix of raw Python and Jinja2 template syntax; the whole complex system for doing inventory and host/group variables; the various modules’ different implementation decisions for how they accept arguments and what they return; and the fact that those modules are wrapping other libraries which you can’t call directly (AWS adds something, wait for boto3 to add it, wait for Ansible to add it, find out that they forgot to add the optional feature you need, repeat). YAML is part of the concern and it especially adds wrinkles like needing dialect-specific editor / formatter / linter support to get the formatting and validation support which using a programming language would give out of the box but most of it comes back to using a document formatting language to write what inevitably needs to be code.
The counter-argument is that it’s easier to start with and that the high-level module interface avoids needing to write as much code. I think that’s a valid goal but it makes me wish there was an easier way to drop code into a project than writing a plugin: imagine if you hit a tricky place with the basic modules but could just drop a .py task in and have the richness of full Python with type validation telling you that an argument is incorrect before your deploy fails 10 minutes in.
How YAML got so popular is a mystery to me. It's a huge pain. Then again, I've given up on fighting it, and simply learned how to use it, since I can't escape Kubernetes anyways.
Also people are mostly arguing for code vs markup. yml, json, xml etc are all the same. Yml just happens to be more compact which helps with visibility in a big file.
It's good at being human-readable. It's basically json with indents and comments. What other configuration format is out there that allows for tree structure and it's easier on humans? (not XML or json).
JSON has some surprises and a lot of limitations, but is so much simpler than YAML that it seems worth putting up with them.
If we consider high composability, non-ambiguity, clarity, expressability (even a word?) as aspects of "human readability" - YAML doesn't go very far in the scale across many of these. A language, with slightly more appealing (yet non-limiting for programmablity) declarative constructs seem very helpful for needs like this.
It would be great to see any spider-web-graph of all these solutions across those aspects and thus help someone to take a wiser decision.
Yaml is just like xml. They all kinda look similar, but can have big and important differences
The successor project, Invoke, was finally released a year or two ago, but now it's unmaintained too.
I much prefer Python to programming in a YAML derivative with multiple bolt-on extension mechanisms but at the end of the day Ansible brings a lot to the table because there are a bunch of people employed by Red Hat to work on it full-time.
There would've been a more active community of companies depending on it and it wouldn't have blocked out on him if it had maintained the momentum it had.
I wish someone would pick that up and continue it — rather then the official version and split into Invoke (which I still don't understand despite a whole week of energy invested).
Honestly fabric was the best thing ever... I still depend on it for personal projects, but sad I can't use it for work projects anymore.
UPDATE: I just found `fab-classic` which is an actively maintained fabric fork with the old API: https://github.com/ploxiln/fab-classic/releases everyone rejoice, for civilized devops is once again upon us, and with the paramiko that is new!
https://en.wikipedia.org/wiki/Infrastructure_as_code#Communi... the space has a lot of players. For upgrading like one VPS and some home servers, I'd probably go with Ansible. It probably has the lowest barrier to entry, and getting an IDE just solves the problem that you created by wanting something in Python. Basic config management doesn't need an IDE.
#!/bin/bash
rm -f /etc/bar
mkdir -p /etc/conf.d
cp -u /srv/src.txt /etc/conf.d/
because Anisble playbook is really just bunch of following statements if (!stuff_exists(stuff))
create_stuff()
which the above utilities in Bash script do with the provided flags.Ansible "declarativeness" isn't anything worthy of worship. It's plain dumb definition of sequence of steps to take with added guard for each step.
So let's be honest and stop pretending that this "declarativeness" is anything novel or of any value worthy of writing sequence of (guarded) commands in ad-hoc YAML language. Just add some sugar for the pattern above to a decent language and that's all that's needed.
I toyed with writing a simple thing, inspired by Fabric, and that was moderately useful:
https://github.com/skx/deployr
Later I tried again, with something more puppet-like, to experiment with how you might handle dependencies in a simple and consistent fashion, ideally without using a complete language (i.e. puppet/ruby):
https://github.com/skx/marionette/
The problem with the simpler approach is that they do only basic things, to support "everything" means writing a hell of a lot of glue, and making a lot of busywork until it is remotely useful to others.
Puppet/CFengine/Chef/Salt/Ansible sometimes seem like they're a dead-end with how many things are moving to master /golden images (packer, etc), and containers.
I wanted to comment on a specific part that mentions that Ansible's YAML is a nightmare to debug.
I wouldn't describe it like that but I'm biased because I've written ARA Records Ansible exactly to make playbooks easier to understand and troubleshoot: https://github.com/ansible-community/ara
I've been using Ansible for many years in different contexts and I think it is easy to get into the trap of "when you have a hammer, everything looks like a nail".
For me, Ansible shines as an excellent abstraction layer for supporting different operating systems or as a glue between different tools.
I am very much a believer of using the right tool for the job. Ansible isn't always the answer and I think that's OK.
The thing I want it a way to keep configuration for a single server in a git repo, and have that server periodically run "git pull" and apply any changes.
I ended up bodging together some custom scripts to do this but I really didn't want to. Maybe I can get pyinfra to do this? I don't want to have to run it on another machine and run commands over ssh though.
I see no practical benefit to requiring devops people to use one scripting language over another, when there are so many equivalent choices to accomplish the same tasks.
As someone else stated the beauty of Ansible is that it abstracts away the most common functions so that the scripts are portable, and the person maintaining the scripts doesn't have to keep up with every syntax change in version if they keep Ansible updated.
Unless you're going to convince individual open source project maintainers to agree to and convert to a somewhat rigid style guide for command line flags, API syntax, and configuration syntax (which no one has managed to do, hence the existence of distros, containers, and Ansible), you're gonna have a hard time convincing anyone to give up on markup languages in deployment tools, I think.
If you want a document language, TOML is a better choice (or JSON or even non-enterprise XML). If you want to write programs, anything else is a better choice. Hashicorp’s HCL is interesting in that it’s much better designed and supported but even there the main thing which makes it work is the presence of an escape hatch when you hit a limitation.
> I see no practical benefit to requiring devops people to use one scripting language over another, when there are so many equivalent choices to accomplish the same tasks.
I actually agree. I am a python programmer, for me, python makes perfect sense. Blogpost doesn't say that you should use python, just that I find pyinfra nice.
Pyinfra examples he shows don't look that different from Ansible YAML. ("apt('nginx', update=True, present=True)")
I'm pretty happy with Ansible, with one exception: speed. I may play with Pyinfra, but I'm heavily invested in Ansible. But if Pyinfra is fast, I might try replacing our Fabric with it. I get pushback about how long Ansible takes for our deploys vs. Fabric.
So why is this ansible plugin such an outlier? How can I be sure that this plugin is actually authored by Microsoft and not by some other entity?
Maybe I'm just being paranoid.
Edit: Ok so if you click the name "Microsoft" in the vscode marketplace it will take you to a list of Microsoft authored plugins, which I guess means the organization name in the marketplace is verified somehow. So yes, I was just being paranoid.
[1] https://marketplace.visualstudio.com/items?itemName=vscoss.v...
Not affiliated with Docker except for using it, and while I do have some thoughts about design choices made by Docker, it's still a very good tool.