The main difference between shell scripts and Ansible playbooks is that shell scripts are imperative, while playbooks are declarative and idempotent.
A shell script will be something like
install this package
create this file
change this line in a configuration file
While a playbook is like
make sure this package is installed
make sure this file exists
make sure this line is like this in this config file
What happens if you want change something in your configuration script? In most cases you can't just replay a shell script, because it will try to do a lot of things that are already done and it is very hard to write idempotent commands.
Ansible on the other hand only performs the tasks in the playbook that need to be performed: if the condition is already satisfied, there's nothing to do.
This is especially convenient if your script fails at some point: you can fix the directive and replay the playbook, and it will restart from where it left off. With shell scripts you have to do it manually (comment out the first part?), which is error-prone and time-consuming.
I will, however, offer that a well-designed shell script should be able to be run many times in a row without causing any problems. The above script is an example of this.
If I wanted to change something in my configuration script, that's totally fine! In fact, I do change it all the time. Since all it does is ask you whether you want homebrew to install something, there is very little risk (if any) of something "going wrong."
To do the same thing using pure shell scripting, you have to write a large number of helper functions to avoid boilerplate. Things like asserting — in an idempotent way — the existence of files (with the right content, the right ownership and mode flags, etc.), services, packages and so on.
Tools like Ansible and Puppet already provide that set of functionality. If you write it yourself, you pretty much end up with something like Ansible, except it's specific only to your use case. Better to focus on commonality.
I'm a Puppet guy myself (although I appreciate the simplicity Ansible can bring to the table), and make extensive use not just of the primitives, but of the ability to bundle primitives as reusable modules. For example, rather than explicitly putting files in /etc/logrotate.d, I define a "logrotate class" and do:
However, this is not merely a macro that is expanded in-place. Rather, it's an object which can be referenced (for example, I can have something else which requires that the object Logrotate::Rotation[postgresql] runs first) as well as "inventoried" (I can ask the system about all the log rotations that have been declared, and use that to drive a UI, for example).
The expressiveness and flexibility of tools like Ansible (which must have something similar) and Puppet is best seen in a multi-node server environment, however.
I understand what you're saying. I just started this a few days ago and wanted to share it with the community. For now, this is more: how I setup my computer than how everyone should do it. But I found that even if a simple bash script would do the same, the ansible roles gives me the possibility to have reusable components. (my boot.sh is terrible, I know, I have to find something else ...)
This yaml approach requires me to know a lot more about existing software than the bash script does. I will need to:
- Read up on the documentation for osxc or battle school
- Look at other configuration files to get a feel for what mine needs to look like.
- Learn about the differences between playbooks or recepies or what have you.
- Download some proprietary software that I will likely never use again.
This is all mental overhead to me.
In comparison, how do you create your own bash script? You already know how to do most of it. If not, just look at the script above. It doesn't require a genius to understand a simple bash function. This approach will take you at most, 5 minutes.
Or maybe I'm just not seeing some huge advantage of these large boxen-esque frameworks for installing some programs.
I tried to learn Puppet in combination with Vagrant for provision rather simple severs, and that was too hard (I had things to do). I then tried to learn Ansible, but didn't get very far. I ended up giving up and writing a shell script that has some simple reusable functions ("is this package installed, if not install it", "does this exact file exist, if not copy it over", etc)
I would rather use Ansible. It seemed like it would fit what I'm trying to do, but everything I can find seems geared towards multiple servers, rather than provisioning a VM and/or an AWS instance identically.
I think you've hit the nail right on the head. The added complexity of these tools, created ostensibly to simplify configuration, simply cannot accomplish what they set out to do by trading in one language for another.
The way my brain works, I’d rather update yaml files than debugging shell script. And because I obsess over this stuff anyway, osxc looks quite appealing.
https://github.com/taylorlapeyre/.files/blob/master/osx/boot...