# On best practices

**URL:** <https://forum.ansible.com/t/on-best-practices/12357>\
**Category:** Ansible Project\
**Created:** [February 14, 2013, 4:41pm UTC](https://forum.ansible.com/t/on-best-practices/12357 "2013-02-14T16:41:20Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Michel\_Blanc1](https://avatars.discourse-cdn.com/v4/letter/m/fbc32d/32.png) [@Michel\_Blanc1](https://forum.ansible.com/u/Michel_Blanc1)\
**Post date:** [February 14, 2013, 4:41pm UTC](https://forum.ansible.com/t/on-best-practices/12357/1 "2013-02-14T16:41:20Z")

</div>

Hi,

Since ansible best practices are being discussed these days, I would  
like to share how I use ansible, and receive your opinions. Wrong way ?  
Suboptimal ? Completely off-track ? Nice ?

I'd like to hear what you think. It's a bit long for the list, so I  
wrote a gist on it :

[https://gist.github.com/leucos/4953943](https://gist.github.com/leucos/4953943)

Thanks for your time if you read it !

M

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [February 14, 2013, 4:59pm UTC](https://forum.ansible.com/t/on-best-practices/12357/2 "2013-02-14T16:59:02Z")

</div>

I generally prefer to not break things up to install vs configure but  
keep one description of desired state when possible.

I also like to keep a playbook for each of my major roles, and that  
playbook just includes the tasks and handlers that they use

For instance, webservers.yml or dbservers.yml or cluster.yml

If I want to do everything, I can have a site.yml that includes all of those.

I think you're a bit more data-driven than most, but I think it's interesting.

I think a playbook per host is suboptimal as you don't want each hosts  
to be unique little snowflakes per se, but rather you should think of  
playbooks per role or function,  
and then use host\_vars/group\_vars to account for variance between  
hosts and groups.

Your 'pivot playbook' is kind of invalid YAML syntax that is covered  
by including inside of a 'tasks' directive.

---

<div class="post-metadata">

**Author:** ![Michel\_Blanc1](https://avatars.discourse-cdn.com/v4/letter/m/fbc32d/32.png) [@Michel\_Blanc1](https://forum.ansible.com/u/Michel_Blanc1)\
**Post date:** [February 14, 2013, 6:05pm UTC](https://forum.ansible.com/t/on-best-practices/12357/3 "2013-02-14T18:05:47Z")

</div>

> I generally prefer to not break things up to install vs configure but  
> keep one description of desired state when possible.

Yes. May be this is overkill. It doesn't really add anything since I  
never call tasks elsewhere.

> I think you're a bit more data-driven than most, but I think it's interesting.

I like variables ineritance and key overriding a lot as you might have  
guessed. I thinks this is pretty cool to maintain setup-wide defaults,  
and change them when nedded without overriding perculiar hosts/groups  
requirements.

> I think a playbook per host is suboptimal as you don't want each hosts  
> to be unique little snowflakes per se, but rather you should think of  
> playbooks per role or function,  
> and then use host\_vars/group\_vars to account for variance between  
> hosts and groups.

Clearly, you're right. However, I have a small setup here and per role  
is almost per host in our shop.

However I will change "top playbooks" to map to a role instead of host,  
this is really the way to go. Who knows, some servers might have  
siblings someday. I already have cases of ucarp connected machines which  
could benefit from the change.

> Your 'pivot playbook' is kind of invalid YAML syntax that is covered  
> by including inside of a 'tasks' directive.

Yes. Thus I think I would have to include the `service/task/*.yml` stuff  
instead of `service/setup.yml`, right ? This is a good excuse to remove  
that service/setup.yml file. However, this implies I always call the top  
level `site.yml` file and can not call a service playbook anymore.

But adding tags in the soup could solve this.

So instead of :

&nbsp;&nbsp;&nbsp;&nbsp;abk -l server.example.org tmux/setup.yml

I could :

&nbsp;&nbsp;&nbsp;&nbsp;abk -l server.example.org site.yml -t tmux

Is this what you were thinking of ?

Thanks for taking time to comment Michael.

M

---

<div class="post-metadata">

**Author:** ![martin\_f\_krafft](https://avatars.discourse-cdn.com/v4/letter/m/8797f3/32.png) [@martin\_f\_krafft](https://forum.ansible.com/u/martin_f_krafft)\
**Post date:** [February 15, 2013, 7:50pm UTC](https://forum.ansible.com/t/on-best-practices/12357/4 "2013-02-15T19:50:40Z")

</div>

also sprach Michel Blanc \<mblanc.networks@gmail.com\> [2013.02.15.0541 +1300]:

> I'd like to hear what you think. It's a bit long for the list, so I  
> wrote a gist on it :
> 
> [https://gist.github.com/leucos/4953943](https://gist.github.com/leucos/4953943)
> 
> Thanks for your time if you read it !

I left a comment on the gist. Why don't you move this to  
a collaborative editor, e.g. [http://titanpad.debian.net](http://titanpad.debian.net) ?

---

<div class="post-metadata">

**Author:** ![kahlil.hodgson](https://avatars.discourse-cdn.com/v4/letter/k/b9bd4f/32.png) [@kahlil.hodgson](https://forum.ansible.com/u/kahlil.hodgson)\
**Post date:** [February 16, 2013, 6:38am UTC](https://forum.ansible.com/t/on-best-practices/12357/5 "2013-02-16T06:38:13Z")

</div>

Thanks for taking the time to gives such a detailed description of your set up. Much food for thought 🙂

First thought is to not conflate the concept of a single playbook and the concept of (one or more) playbooks bundled with a set of files, handlers, vars\_files and tasks. Perhaps we could borrow the term 'bundle' from bcfg2 for the latter?

I like the idea of making playbook bundles per-service or per-role (one or more services grouped, like, say, postfix and dovecot). This is what I do too. 🙂

I used to build host-agnostic playbooks like you describe, but ran into a number of difficulties getting it to manage certain situations without loosing the wonderful clarity and simplicity of ansible.

Then I discovered a little gem buried in the documentation.

"It is the purpose of a play to map a selection of hosts to tasks"

Eureka moment! Playbooks are data too!

The hosts file defines hosts and groups;  
The host\_vars and group\_vars assign data to hosts;  
Playbooks define mappings from hosts (or groups) to tasks.

I think trying to shoehorn the 'host to task' mapping into the inventory data is an exercise in futility, or at least I found it to be.

I'm currently reworking my service bundles to contain separate playbooks for each host (or group of hosts) that need to be managed differently. Being able to include task files and even other playbooks means these playbooks can be quite short and simply express the required host to task mapping, as data. This also means I can run playbooks without having to use overly complicated command line arguments (or script wrappers).

Does this make any sense?

Cheers,

Kal

---

<div class="post-metadata">

**Author:** ![Michel\_Blanc1](https://avatars.discourse-cdn.com/v4/letter/m/fbc32d/32.png) [@Michel\_Blanc1](https://forum.ansible.com/u/Michel_Blanc1)\
**Post date:** [February 20, 2013, 1:53pm UTC](https://forum.ansible.com/t/on-best-practices/12357/6 "2013-02-20T13:53:32Z")

</div>

Hi,

Better late than never, thanks guys for commenting on my pbook extract.  
A few replies here, sorry for being long.

TL;DR: on the difficulty of having host-agnostic per-service playbooks

> > I'd like to hear what you think. It's a bit long for the list, so  
> > I wrote a gist on it :
> > 
> > [https://gist.github.com/leucos/4953943](https://gist.github.com/leucos/4953943)
> > 
> > Thanks for your time if you read it !
> 
> I left a comment on the gist. Why don't you move this to

Thanks, I've reproduced them here.

> a collaborative editor, e.g. [http://titanpad.debian.net](http://titanpad.debian.net) ?

Well, you can fork gists too though I agree hat for gists is it not  
really convenient (no PR AFAIK).  
But done anyway :

[http://titanpad.com/RFU9FrzGGS](http://titanpad.com/RFU9FrzGGS)

I'm in the process of curating sensible data from my playbooks. When  
done, I'll create a GH repos. We need more playbook examples, I'll try  
to add my 2 cents to the mix.

> I have two comments:
> 
> Wouldn't it be better not to include the tmux playbook on machines  
> that don't get tmux, rather than turning it into a play  
> conditional play?

Yes, sure. This is why I have 'per machine top level' playbooks.  
For instance, goat.example.com will have a goat.e.c.yml playbook.  
So yes, "only\_if: ${tmux.install}" is probably an overkill safety  
measure in this case.

> A case could be made for tmux.install==False causing tmux to be  
> purged from the system, but you don't do that.

Yes right, thats is an idea ! I wouldn't do that right now, since I'm  
in the process of migrating hosts under ansible management. Some of  
them are partly managed with ansible, and some of them appear in  
inventory jyst because their IP is needed somewhere else (firewall  
deployment on other hosts).

So I wouldn't like ansible to uninstall my cyrus server just because I  
messed up things.  
When all hosts will be under ansible management, this is definitely a  
great idea.

> And even if you did, I think there are numerous cases where  
> parametrisation via variables should actually affect the  
> composition of the playbook, not just the behaviour.

Yes, this is true, and I'm still scratching my head for this. I might  
end up with generic services playbooks, and some specific  
configuration playbooks. For instance, a generic postfix playbook that  
uses a relayhost (just for emailing out stuff), and a dedicated,  
specific playbook for our much more complex MX.

Something like :  
- include: host-specific/smtp.example.org/setup.yml  
&nbsp;&nbsp;# contains postfix configuration for smtp.example.org

in the "host-dedicated top level playbook" could do the trick.  
However, it would kill idempotency since configurations installed by  
the postfix "service playbook" would be overwritten at every run (and  
vice-versa).

> Have a look at  
> [https://groups.google.com/forum/?fromgroups=#!topic/ansible-project/HetiQdNKOj4](https://groups.google.com/forum/?fromgroups=#!topic/ansible-project/HetiQdNKOj4)

and the referenced post to the salt-users list and chime in (on the

> ansible list of course).

Thanks a lot for your comments Martin !

> I'm currently reworking my service bundles to contain separate  
> playbooks for each host (or group of hosts) that need to be  
> managed differently.

That could be interesting to see. Do you have an example ?

> Being able to include task files and even other playbooks means  
> these playbooks can be quite short and simply express the required  
> host to task mapping, as data. This also means I can run playbooks  
> without having to use overly complicated command line arguments (or  
> script wrappers).

I personnaly end up running stuff like this :

abk -l host.example.org h.e.o.yml

where h.e.o.yml is a "top level" playbook including service playbooks :

---

<div class="post-metadata">

**Author:** ![kahlil.hodgson](https://avatars.discourse-cdn.com/v4/letter/k/b9bd4f/32.png) [@kahlil.hodgson](https://forum.ansible.com/u/kahlil.hodgson)\
**Post date:** [February 22, 2013, 7:49am UTC](https://forum.ansible.com/t/on-best-practices/12357/7 "2013-02-22T07:49:09Z")

</div>

Suppose I'm managing postfix for a mail hub with a secondary MX, but I also have a bunch of other servers that I want to run a local relay on.

Lets start with the following layout:

postfix/  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;files/  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handlers.yml  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tasks/  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setup.yml  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configure.yml  
&nbsp;&nbsp;whatever.yml  
&nbsp;&nbsp;...

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mail-hub.yml  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local-relay.yml

with the following playbooks
