# Playbook structure

**URL:** <https://forum.ansible.com/t/playbook-structure/36607>\
**Category:** Ansible Project\
**Created:** [May 9, 2022, 8:06pm UTC](https://forum.ansible.com/t/playbook-structure/36607 "2022-05-09T20:06:59Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Marc\_Haber](https://avatars.discourse-cdn.com/v4/letter/m/a3d4f5/32.png) [@Marc\_Haber](https://forum.ansible.com/u/Marc_Haber)\
**Post date:** [May 9, 2022, 8:06pm UTC](https://forum.ansible.com/t/playbook-structure/36607/1 "2022-05-09T20:06:59Z")

</div>

Hi,

after using ansible for quite a while, my project to manage my own  
servers has grown to a respectable size. I was a puppet user before, so  
I have a single big playbook containing everything. I have the feeling  
this is like holding ansible wrong, and I also have the feeling that I  
have my playbook structured wrong. Judging from the single "name"  
setting, I took the wrong turn in the very beginning. The playbook does  
what it is intended to do, however.

Here is an excerpt from my playbook.

---

<div class="post-metadata">

**Author:** ![Dick\_Visser](https://avatars.discourse-cdn.com/v4/letter/d/d9b06d/32.png) [@Dick\_Visser](https://forum.ansible.com/u/Dick_Visser)\
**Post date:** [May 10, 2022, 6:30am UTC](https://forum.ansible.com/t/playbook-structure/36607/2 "2022-05-10T06:30:13Z")

</div>

> Hi,
> 
> after using ansible for quite a while, my project to manage my own  
> servers has grown to a respectable size. I was a puppet user before, so  
> I have a single big playbook containing everything. I have the feeling  
> this is like holding ansible wrong, and I also have the feeling that I  
> have my playbook structured wrong. Judging from the single "name"  
> setting, I took the wrong turn in the very beginning. The playbook does  
> what it is intended to do, however.
> 
> Here is an excerpt from my playbook.
> 
> ---  
> - name: apply common configuration  
> &nbsp;&nbsp;hosts: all  
> &nbsp;&nbsp;remote\_user: zgansible  
> &nbsp;&nbsp;become: "yes"

What is the reason for quoting this boolean? It is usually done to force it to be a string, but AFAIK this parameter requires a boolean.

> &nbsp;&nbsp;tasks:  
> &nbsp;&nbsp;⦙ - name: install ansible dependencies  
> &nbsp;&nbsp;⦙ ⦙ apt:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ name: ['python3', 'python3-apt']  
> &nbsp;&nbsp;⦙ ⦙ ⦙ state: present  
> &nbsp;&nbsp;⦙ - name: get package facts  
> &nbsp;&nbsp;⦙ ⦙ package\_facts:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ manager: "auto"  
> &nbsp;&nbsp;⦙ ⦙ tags: always  
> &nbsp;&nbsp;⦙ - name: print facts  
> &nbsp;&nbsp;⦙ ⦙ debug:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ var: ansible\_facts  
> &nbsp;&nbsp;⦙ ⦙ tags: [never, debug, printfacts]  
> &nbsp;&nbsp;⦙ - name: print package facts  
> &nbsp;&nbsp;⦙ ⦙ debug:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ var: ansible\_facts.packages  
> &nbsp;&nbsp;⦙ ⦙ tags: [never, debug, printpackagefacts]  
> &nbsp;&nbsp;⦙ - include\_role:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ name: clean-motd  
> &nbsp;&nbsp;⦙ ⦙ ⦙ apply:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - clean-motd  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - clean-all  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - never  
> &nbsp;&nbsp;⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ - clean-motd  
> &nbsp;&nbsp;⦙ ⦙ ⦙ - clean-all  
> &nbsp;&nbsp;⦙ ⦙ ⦙ - never  
> &nbsp;&nbsp;⦙ - include\_role:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ name: sysctl  
> &nbsp;&nbsp;⦙ ⦙ ⦙ apply:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - sysctl  
> &nbsp;&nbsp;⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ - sysctl  
> (LOTS of other include\_role stanzas defining roles that are on all machines)
> 
> - name: apply configuration for bind9 servers  
> &nbsp;&nbsp;hosts:  
> &nbsp;&nbsp;⦙ - alemana  
> &nbsp;&nbsp;⦙ - cadencia  
> &nbsp;&nbsp;⦙ - gancho  
> &nbsp;&nbsp;⦙ - impetus  
> &nbsp;&nbsp;⦙ - lasso  
> &nbsp;&nbsp;⦙ - torres  
> &nbsp;&nbsp;⦙ - dns1  
> &nbsp;&nbsp;remote\_user: zgansible  
> &nbsp;&nbsp;become: "yes"  
> &nbsp;&nbsp;vars:  
> &nbsp;&nbsp;⦙ bind\_role: "{{ (bind|default({}))|combine(bind\_group|default({}), recursive=true, list\_merge='append') }}"  
> &nbsp;&nbsp;tasks:  
> &nbsp;&nbsp;⦙ - include\_role:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ name: bind9  
> &nbsp;&nbsp;⦙ ⦙ ⦙ apply:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - bind9  
> &nbsp;&nbsp;⦙ ⦙ tags:  
> &nbsp;&nbsp;⦙ ⦙ ⦙ - bind9  
> \> - name: apply configuration for DHCP servers  
> &nbsp;&nbsp;&nbsp;&nbsp;hosts:  
> &nbsp;&nbsp;&nbsp;⦙ - chasse  
> &nbsp;&nbsp;&nbsp;⦙ - cadencia  
> &nbsp;&nbsp;&nbsp;remote\_user: zgansible  
> &nbsp;&nbsp;&nbsp;become: "yes"  
> &nbsp;&nbsp;&nbsp;tasks:  
> &nbsp;&nbsp;&nbsp;⦙ - include\_role:  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ ⦙ name: isc-dhcp-server  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ ⦙ apply:  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ tags:  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ ⦙ ⦙ ⦙ - isc-dhcp-server  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ tags:  
> &nbsp;&nbsp;&nbsp;⦙ ⦙ ⦙ - isc-dhcp-server
> 
> Is this the way to do it? Any comments will be appreciated.

I don't see anything totally wrong with the above approach.  
Perhaps try to avoid the inline lists but that's cosmetics.

> In the other news, where would I correctly place (and activate) this handler:
> 
> ---  
> - name: apt update  
> &nbsp;&nbsp;&nbsp;command: "apt-get update"
> 
> if I intend to notify this handler from any role that might use the apt  
> provider to install packages?

What is the use case for this?  
If you want to make sure this is always run prior to any package task, then you should use the update\_cache parameters of the apt module:

[https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt\_module.html#parameter-update\_cache](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html#parameter-update_cache)

Dick

---

<div class="post-metadata">

**Author:** ![Marc\_Haber](https://avatars.discourse-cdn.com/v4/letter/m/a3d4f5/32.png) [@Marc\_Haber](https://forum.ansible.com/u/Marc_Haber)\
**Post date:** [May 12, 2022, 10:57am UTC](https://forum.ansible.com/t/playbook-structure/36607/3 "2022-05-12T10:57:28Z")

</div>

Hi Dirk,

> \> after using ansible for quite a while, my project to manage my own  
> \> servers has grown to a respectable size. I was a puppet user before, so  
> \> I have a single big playbook containing everything. I have the feeling  
> \> this is like holding ansible wrong, and I also have the feeling that I  
> \> have my playbook structured wrong. Judging from the single "name"  
> \> setting, I took the wrong turn in the very beginning. The playbook does  
> \> what it is intended to do, however.  
> \>  
> \> Here is an excerpt from my playbook.  
> \>  
> \> ---  
> \> - name: apply common configuration  
> \> hosts: all  
> \> remote\_user: zgansible  
> \> become: "yes"
> 
> What is the reason for quoting this boolean? It is usually done to force it  
> to be a string, but AFAIK this parameter requires a boolean.

Historical reasons, fixed. I probably didnt know any better, and it's  
still a matter of try-and-err whether to find out whether ansible  
wants/insists on things being quoted or not.

[snip]

> I don't see anything totally wrong with the above approach.  
> Perhaps try to avoid the inline lists but that's cosmetics.

How would I write them any better?

> \> In the other news, where would I correctly place (and activate) this handler:  
> \>  
> \> ---  
> \> - name: apt update  
> \> command: "apt-get update"  
> \>  
> \> if I intend to notify this handler from any role that might use the apt  
> \> provider to install packages?
> 
> What is the use case for this?  
> If you want to make sure this is always run prior to any package task, then  
> you should use the update\_cache parameters of the apt module:
> 
> [https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt\_module.html#parameter-update\_cache](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html#parameter-update_cache)

updating the package lists after fiddling with things in /etc/apt, for  
example preparing a release upgrade or adding an external repository  
(docker \*cough\*). Doing an apt update right before any check whether any  
required package is already installed seems overkill, but I need to  
ponder about that.

Greetings  
Marc

---

<div class="post-metadata">

**Author:** ![racke](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/racke/32/4767_2.png) [@racke](https://forum.ansible.com/u/racke)\
**Post date:** [May 12, 2022, 1:08pm UTC](https://forum.ansible.com/t/playbook-structure/36607/4 "2022-05-12T13:08:18Z")

</div>

> Hi,
> 
> after using ansible for quite a while, my project to manage my own  
> servers has grown to a respectable size. I was a puppet user before, so  
> I have a single big playbook containing everything. I have the feeling  
> this is like holding ansible wrong, and I also have the feeling that I  
> have my playbook structured wrong. Judging from the single "name"  
> setting, I took the wrong turn in the very beginning. The playbook does  
> what it is intended to do, however.

My two cents:

- host name / remote user should be in the inventory and not in the playbook  
- consider using import\_role instead of include\_role

Regards  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Racke

---

<div class="post-metadata">

**Author:** ![racke](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/racke/32/4767_2.png) [@racke](https://forum.ansible.com/u/racke)\
**Post date:** [May 12, 2022, 1:19pm UTC](https://forum.ansible.com/t/playbook-structure/36607/5 "2022-05-12T13:19:54Z")

</div>

> Hi Dirk,
> 
> > > after using ansible for quite a while, my project to manage my own  
> > > servers has grown to a respectable size. I was a puppet user before, so  
> > > I have a single big playbook containing everything. I have the feeling  
> > > this is like holding ansible wrong, and I also have the feeling that I  
> > > have my playbook structured wrong. Judging from the single "name"  
> > > setting, I took the wrong turn in the very beginning. The playbook does  
> > > what it is intended to do, however.
> > > 
> > > Here is an excerpt from my playbook.
> > > 
> > > ---  
> > > - name: apply common configuration  
> > > &nbsp;&nbsp;&nbsp;hosts: all  
> > > &nbsp;&nbsp;&nbsp;remote\_user: zgansible  
> > > &nbsp;&nbsp;&nbsp;become: "yes"
> > 
> > What is the reason for quoting this boolean? It is usually done to force it  
> > to be a string, but AFAIK this parameter requires a boolean.
> 
> Historical reasons, fixed. I probably didnt know any better, and it's  
> still a matter of try-and-err whether to find out whether ansible  
> wants/insists on things being quoted or not.
> 
> [snip]
> 
> > I don't see anything totally wrong with the above approach.  
> > Perhaps try to avoid the inline lists but that's cosmetics.
> 
> How would I write them any better?
> 
> > > In the other news, where would I correctly place (and activate) this handler:
> > > 
> > > ---  
> > > - name: apt update  
> > > &nbsp;&nbsp;&nbsp;&nbsp;command: "apt-get update"
> > > 
> > > if I intend to notify this handler from any role that might use the apt  
> > > provider to install packages?
> > 
> > What is the use case for this?  
> > If you want to make sure this is always run prior to any package task, then  
> > you should use the update\_cache parameters of the apt module:
> > 
> > [https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt\_module.html#parameter-update\_cache](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html#parameter-update_cache)
> 
> updating the package lists after fiddling with things in /etc/apt, for  
> example preparing a release upgrade or adding an external repository  
> (docker \*cough\*). Doing an apt update right before any check whether any  
> required package is already installed seems overkill, but I need to  
> ponder about that.

You can add/modify/delete the external repo with Ansible and run the apt update only when the repo changed.

The equivalent for "apt-get update" is:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- name: Update APT cache  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apt:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update\_cache: yes

Regards  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Racke

---

<div class="post-metadata">

**Author:** ![dnmvisser](https://avatars.discourse-cdn.com/v4/letter/d/8e8cbc/32.png) [@dnmvisser](https://forum.ansible.com/u/dnmvisser)\
**Post date:** [May 12, 2022, 8:21pm UTC](https://forum.ansible.com/t/playbook-structure/36607/6 "2022-05-12T20:21:07Z")

</div>

stylistic nit pick

> > tasks:  
> > ⦙ - name: install ansible dependencies  
> > ⦙ ⦙ apt:  
> > ⦙ ⦙ ⦙ name: ['python3', 'python3-apt']  
> > ⦙ ⦙ ⦙ state: present

&nbsp;&nbsp;&nbsp;- name: install ansible dependencies  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apt:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- python3  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- python3-apt  
&nbsp;&nbsp;&nbsp;&nbsp;state: present

---

<div class="post-metadata">

**Author:** ![Marc\_Haber](https://avatars.discourse-cdn.com/v4/letter/m/a3d4f5/32.png) [@Marc\_Haber](https://forum.ansible.com/u/Marc_Haber)\
**Post date:** [May 13, 2022, 10:24am UTC](https://forum.ansible.com/t/playbook-structure/36607/7 "2022-05-13T10:24:30Z")

</div>

Fair enough, thanks. Those hints are the most important.

Greetings  
Marc

---

<div class="post-metadata">

**Author:** ![Nico\_Kadel-Garcia](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/nico_kadel-garcia/32/9998_2.png) [@Nico\_Kadel-Garcia](https://forum.ansible.com/u/Nico_Kadel-Garcia)\
**Post date:** [May 13, 2022, 11:04am UTC](https://forum.ansible.com/t/playbook-structure/36607/8 "2022-05-13T11:04:08Z")

</div>

It's gotten a bit strange out there. I'd encourage you to focus your  
installation on "ansible-core", which contains the relevant python  
modules and executable scripts, and entirely ignore the upstream  
"ansible" package unless you have a compelling need for 100 third  
party modules in a semi-organized and monolithic bundle taking up  
roughly half a Gig of local disk space. It's not really useful for  
most ansible server setups.
