What if Ansible used XML for configuration management?
djwonk.tumblr.com
djwonk.tumblr.com
A very valid complaint would be that Ansible isn't idempotent, which I think is what the author was trying to get at. Nixos would be a great example of an idempotent system, and you might be able to convince me that Docker would qualify, too. As much as I like Ansible, its lack of true idempotence is a weakness.
But that has nothing to do with yaml v. XML v. anything else. You could trivially write an idempotent description language in XML, and you can trivially write a horrible state-based system in a Haskell DSL or Prolog. As far as I can tell, the author is complaining that people think that Ansible is idempotent because it has yaml. That is incorrect, but I don't think that it'd be better or worse if they'd pick something else; merely more verbose. (Look at Maven and Gradle for an example.)
I'm really interested to see if or how a community with diverse preferences (developers and system administrators) might agree on a small number of configuration management tools. Or are we destined to have these tools splinter across languages?
> I think the choice of language for these tools matters
> a lot
I read the post, and still don't know _why_ you think it matters, when comparing two data-interchange languages.I think Ansible aims to be more idempotenty than other environments, and I think it succeeds there. The lack of something like Chef databags helps, as does its insistence that $SCM is the source of truth. But it doesn't take a holistic enough stance to really get all the way there. It's very difficult to do things like handle the transition from one version of a play book to another sometimes; while running a given playbook on a given blank system may be idempotent, it can't actually reliably model state transitions. In other words, it's only got half of the puzzle.
This is why I don't use cmd in general, and if I do I try to make sure that it's an idempotent command.
Ansible playbooks are not always declarative. There is often stuff that looks like this:
---
---
# Launch Job to count occurance of a word.
- hosts: $server
user: root
tasks:
- name: copy the file
copy: src=inputfile dest=/tmp/inputfile
- name: upload the file
shell: ...
<more names and shell pairs ...>
---That is just specifying a set of steps. So then it calls for for loops, if conditions, and so on.
I noticed that pattern in examples when looking at Ansible and kind of shook my head.
But oh well, I guess, it depends on how you arrived at Ansible. I think if you view it as "better than SSH-ing and running shell scripts". Ok it looks nice. But if you want a more mature declarative based configuration system, then maybe you'll start to see various flaws or design issues with it.
Chef seems more powerful. Also played with saltstack. I like saltstack better so far but aside from playing with it still use shell scripts and OS packaging pre-/post- install scripts to handle tasks like these.
Further, this (using a data language as a programming language) isn't without precedent. Both XSL and Ant have standard conditionals, loops, etc available for use.
Yes, XSL and Ant got there first, but what fraction of us would like to see the same decision made again? :)
That said, I'm starting to warm to the fact that Django uses straight Python for its settings. If you're going to use a Turing-complete language to write your config file, might as well use a familiar one.
I actually like the idea behind XSD - I have encountered situations where a "strongly-typed" configuration file would have made a lot of sense. Only problem is that the kinda-like-XML-but-not-really format of XSD is so clunky it becomes a second source of frustration.
YAML is kind of sucky as a data transfer format (chopped up YAML is still valid which leads to all kinds of screwed up behavior), but its mirror equivalent JSON is good for that. Equally, JSON sucks for declarative configuration but YAML really shines.
Django's settings file is also one of the thornier bits of django. I'm not sure if should necessarily have become declarative, but making it a monolithic python file causes a lot of headaches with integrating modules, state changes, etc. The fact that you can often move a bit of config from one end of the file to the other and change the behavior completely is a bit screwed up. I think it would work better if it were a bit more ansible-y.
I can see where you're coming from regarding Django's settings file. Lord knows how many hours I've wasted hunting down stray configurations thanks to frameworks which abuse inheritance for its settings config (I'm looking at you, Mezzanine). Still, the fact that it is Python, and can therefore be debugged like any other Python script instead of obeying its own special syntax, is a plus in my books.
Occasionally, it would spawn a whole new language: http://www.lua.org/
In chef's case, I would rather write simple classes & functions in plain ruby than use the DSL and write "Lightweight Resource Providers".
In ansible's case, I even did a little experiment to show what it would look like to use & call ansible modules as normal python code:
https://github.com/lost-theory/ansible/blob/module_experimen...
https://groups.google.com/d/topic/ansible-project/Zv3Veo77gP...
I would love to see a CM tool that embraced plain python or plain ruby and not try to go the pseudo-"declarative" route, which ends up being IMO too constraining for not much benefit and needlessly reinventing a bunch of wheels (e.g. looping & conditionals, as the article mentions).
I haven't worked with Chef so I can't comment, but I work extensively on the puppet-openstack project and my experience is that this aversion to actual languages is part of a pipe dream. The only people who are able to work with the modules in any meaningful way are the ones that understand the Puppet DSL and runtime in its entirety, and it's not much simpler than the Ruby language it's based on.
Honestly I don't know what the solution is: part of the DevOps movement is introducing development practices to the management of systems, but that brings with it an inherent requirement that the operators actually embrace the development practices. A quick example of where this can easily fall down is if you maintain a puppet environment of any complexity, you'll end up keeping both the data inputs and the modules in git repos, but if your sysadmins aren't comfortable with git, the adoption simply won't happen.
As someone who is traditionally more dev side, but has done a lot of casual system administration, this part of things like chef and puppet drives me nuts. I don't want to version my infrastructure in git and then throw it, with no versioning context, up to a server and have it version it again in its own unique, quirky, and honestly haphazard way.
- command: chdir=/foo echo {{ bar }}
when: bar is defined
Really parses down to something like: - action:
- module: command
- arguments:
- chdir: /foo
- command: echo {{ bar }}
- when: bar is defined
More parsing is done by ansible than is done by YAML. I'm not necessarily saying it's bad, but it definitely leads to some gotchas and weirdnesses.How it mixes in Jinja2 is also strange. In the above example, there are two expressions: {{ bar }} and 'bar is defined'. Normally if you paired a templating language with a text format, you would expect the templating language to apply to the whole file. Ansible applies it afterwards, and selectively. That's the right thing to do, but it does make it confusing.
Many people choose ansible because they don't want to learn Ruby as well as a CM tool; ansible isn't much simpler. I'm not a huge fan of ansible, it's just better than everything else I've encountered so far.
Where Ansible really shines is giving you a huge library of quality plugins/components and a simple YAML-based DSL for composing those plugins. Want to spin up an EC2 instance, copy over your code, and ensure a service is started? No problem, it's a 4 or 5 line Ansible script. When you want to do something more advanced, look at the extension points Ansible provides to plugin your own code: http://docs.ansible.com/developing_plugins.html
- apt: name=apache2 state=present
Then, on day 2, you realize that Apache isn't hip, so you switch to nginx instead: - apt: name=apache2 state=absent
- apt: name=nginx state=present
It works, but you're stuck with entries in your playbook that are there for purely historical reasons.I think that Ansible is still a transitional glue tech though, and projects like flynn.io may move things forward by making the CM part of the infrastructure a developer task vs. a devops one.
Ansible is 100% intended for configuration management. Configuration is by its very nature declarative, so in any case if you were doing a lot of custom procedural code for configuration you're probably doing something a bit wrong.
https://github.com/technomancy/leiningen/blob/stable/sample....
To be fair, ansible allows the same sort of behavior with cmd, letting you turn your playbook into one long overly verbose bash script.
I have yet to see any code abortions on a par with what I've seen with ant or maven with that, yet, though.
I ended up integrating this into all my projects:
http://blog.cliffano.com/2014/04/06/human-readable-ansible-p...
Which fixes the problem (sort of), but I really don't understand why the default isn't looking something like that.
It's a real pain parsing through some JSON with a ton of \n...\n...\n...\n's in order to find the source of the errors.
I have to admit that I'm a fan of turtles -- the same kind of turtles -- all the way down. Many of the abstractions I see in configuration management tools seem to be fancy names for modules. I don't see why a role, a playbook, a play, and a task really need to be different things at all. Why is the hierarchy necessary?
Absolutely. IMO, the top layer should be a summary of what the configuration manager will be doing and should have the project-specific data in it. The rest should be reusable modules. When you let a full program language into the top layer, you inevitably get people trying to put smaller routines in the top level itself mixed in with reusable modules, which results in bloated spaghetti.
To make it easy to extract out reusable code in a consistent way.
They aren't all necessary, though. If you have a very simple playbook it can go all in one file.
Sort of like how python has classes (which correspond to roles), but you're not forced to use them.
Thank God IntelliJ treats Spring XML as Java code, because so much logic and conditionals and variables live in those files. The actual program can be very different than what you would expect only looking at the Java files.
It pains me to see other tools make the same foolish mistake, even if I don't happen to use it.
This is pretty much why I love fucking shell scripts. http://fuckingshellscripts.org/
Also, because Bash is a particularly horrible language. I have a lot of experience writing bash scripts, and I hate bash.
I have a visceral hatred, a la Erik Naggum, towards XML. His arguments against XML capture a lot of my feelings, so I won't rehash them here.