# Include playbook but limit to specific host

**URL:** <https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816>\
**Category:** Get Help\
**Created:** [January 24, 2025, 4:15pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816 "2025-01-24T16:15:42Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![romgo](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/romgo/32/5202_2.png) [@romgo](https://forum.ansible.com/u/romgo)\
**Post date:** [January 24, 2025, 4:15pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/1 "2025-01-24T16:15:42Z")

</div>

Hello,

I have a common.yml playbook which manage all the system default ( resolv.conf, snmp, ntp…) which must be call for all servers so the code look like this :

```auto
---
- name: Commons conf
  hosts: all
  gather_facts: true
  roles:
    - apt
    - resolv
    - snmpd
    - ntpd

```

this playbook works well.  
When I create a VM in my workflow, I create a new playbook which needs to include the common.yml playbook and include custom config with new roles for this server. This will define the full state of the VM ensuring we don’t rewrite code or forget to include sorole each time.

This is my issue here, I don’t find a clean way to create a playbook which doesn’t need to use --limit option to only apply to the selected target.

For the following code I need to use --limit to avoid commons-playbook to be executed on all target.

```auto
---
- name: Run commons-playbook first
  import_playbook: commons-playbook.yml

- name: Install and Configure
  hosts: nagios
  gather_facts: true
  roles:
    - nagios
    - php

```

So I tried to define a variable with the hostname and to provide this variable to host field, but I didn’t manage to make it work :

```auto
---
- name: Playbook for specific servers
  hosts: localhost
  vars:
    target_hosts:
      - server1
      - server2

- name: Nodejs install and configuration
  hosts: "{{ target_host }}"
  gather_facts: true
  import_playbook: common.yml

- name: Nodejs install and configuration
  hosts: "{{ target_host }}"
  gather_facts: true
  roles:
      - php
      - webserver

```

Any help appreciated !

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [January 24, 2025, 4:24pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/2 "2025-01-24T16:24:01Z")

</div>

so several issues with yours solution:

- vars you define in a play, won’t be visible to other plays, it is not the same scope, either set them as ‘extra vars’ and pass them in when invoking the playbook or set them per play that needs them .
- import\_playbook is not valid inside a play, having it with `hosts:` or `gather_facts:` won’t work as it needs to be at the same level of other plays, not inside one.

working example with embedded vars:

```auto
- name: Playbook for specific servers
  hosts: localhost
  
- name: Nodejs install and configuration
  import_playbook: common.yml
  vars:
    target_hosts:
      - server1
      - server2

- name: Nodejs install and configuration
  hosts: "{{ target_hosts }}"
  gather_facts: true
  vars: # this one makes very little sense, might as well just use hosts: server1,server2
    target_hosts:
      - server1
      - server2
  roles:
      - php
      - webserver

```

Otherwise just remove the target\_hosts var from play and call it with `-e target_hosts=server1,server2'`. The other thing i recommend is using `--limit server1,server2` and leaving the plays to either `hosts: all` or an appropriate group.

---

<div class="post-metadata">

**Author:** ![romgo](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/romgo/32/5202_2.png) [@romgo](https://forum.ansible.com/u/romgo)\
**Post date:** [January 24, 2025, 4:44pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/3 "2025-01-24T16:44:44Z")

</div>

> [@bcoca](#):
>
> ```auto
> - name: Playbook for specific servers
> hosts: localhost
>   
> - name: Nodejs install and configuration
> import_playbook: common.yml
> vars:
> target_hosts:
> - server1
> - server2
> 
> - name: Nodejs install and configuration
> hosts: "{{ target_hosts }}"
> gather_facts: true
> vars: # this one makes very little sense, might as well just use hosts: server1,server2
> target_hosts:
> - server1
> - server2
> roles:
> - php
> - webserver
> 
> ```

thanks a lot. indeed this is working.  
I agree this doesn’t look like very clean because I set multiple times the target.

Maybe I can set target\_hosts at a global variable in the playbook ?

I was looking for this because using --limit can be ‘forgotten’ and I fear the risk the playbook to be played against unwanted target.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [January 24, 2025, 6:16pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/4 "2025-01-24T18:16:12Z")

</div>

The only ‘global’ is extra vars and they cannot be set in the playbook. Another option is to have a assert in the first playbook that looks for `ansible_limit` to be populated

---

<div class="post-metadata">

**Author:** ![romgo](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/romgo/32/5202_2.png) [@romgo](https://forum.ansible.com/u/romgo)\
**Post date:** [January 27, 2025, 9:02am UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/5 "2025-01-27T09:02:48Z")

</div>

Thanks.  
I am wondering if I am using ansible the right way here.  
I got puppet background I was able to manage this situation, but with ansible I feel I’m not using it the right way.

So what would be the way to manage a commons roles and specific roles for a given host ?

I see two option so far but for each I have issues :

- don’t create a common.yml playbook, instead put all the required roles into the playbook for each roles : ok for few host but when you have hundreds of host and playbook, If you need to add a ‘common’ roleit would be very time consumming with very little added value for this task and error prone (forget one playbook).

- Create a common role instead of a playbook : I don’t like the ideal to have a ‘garbage’ role because in common we have lot of service managed snmpd,rsyslog, ssh…

I read the documentation and seems that the commons role is something recommended by ansible.

Looking for advice thanks !

---

<div class="post-metadata">

**Author:** ![anon81884396](https://avatars.discourse-cdn.com/v4/letter/a/b782af/32.png) [@anon81884396](https://forum.ansible.com/u/anon81884396)\
**Post date:** [January 27, 2025, 1:55pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/6 "2025-01-27T13:55:54Z")

</div>

I’ve worked in several orgs where the question was “puppet or ansible”. To me this is like asking “should I use a hammer or a screwdriver to build a house?” They’re complementary tools and there isn’t a reason you can’t use both where it’s appropriate.

In my experience, ansible is good at the following:

- Performing ad-hoc or irregular activities such as patching or software installation or SSL certificate operations (for example)
- Performing actions in a specific order (it is possible to do this with Puppet but it is easier in ansible)

Ansible lacks in the following:

- Enforcing standardized system and application configurations against a vast array of different hosts (the puppet agent is good at this, as you know)
  - Hiera can be a powerful tool to cascade standards, there isn’t anything like it for ansible.

- Dependency management is easier with puppet than ansible

Ansible’s strengths tend to be puppet’s weaknesses, and vice versa.

Is your management making you go down the path of having ansible replace puppet, or are you just interested in exploring ansible?

---

<div class="post-metadata">

**Author:** ![romgo](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/romgo/32/5202_2.png) [@romgo](https://forum.ansible.com/u/romgo)\
**Post date:** [January 27, 2025, 2:27pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/7 "2025-01-27T14:27:27Z")

</div>

> [@anon81884396](#):
>
> Is your management making you go down the path of having ansible replace puppet, or are you just interested in exploring ansible?

Thank you very interesting feedback.

For the context I moved to a new company, ansible was useed only for some random task. My objective now is to fully managed the VM throught ansible and for this I split my view in two parts : commons services (i.e snmpd) VS specific services (i.e apache2)

To clarify, I’m not looking to oppose ansible to puppet. Just this is my experience so I’m always referencing to what I’ve done with puppet (this is maybe a bad idea!) So far I found log of similiarity which allow me to have a fast learning curve on Ansible.

I know with tools like this we can do the same things in several ways, but i’m lloking for the “proper” way from ansible point of view.  
I feel on this matter I’m missing something or the tool on this specific aspect might not be able to answer. This is way I’m trying to have some feedback.

Hope this clarify!

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [January 27, 2025, 3:22pm UTC](https://forum.ansible.com/t/include-playbook-but-limit-to-specific-host/39816/8 "2025-01-27T15:22:03Z")

</div>

There are countless ways this can be done I not sure there is a “proper” way? 🤷

The way I’m doing this is one role per service, eg an Apache or SSH role and I have one main `all.yml` playbook that contains all the roles like this (I could have `ssh` set to `true` for all hosts here but I don’t):

```yaml
- name: All servers all roles
  become: true 
  gather_facts: true
  hosts:
    - all
  roles:
    - role: ssh
      when:
        - ssh is defined
        - ssh | bool
    - role: apache
      when:
        - apache is defined
        - apache | bool

```

For each role there is a variable that matches the role name that is `false` by default, for example for the Apache role `apache` is `false` and then the Apache role tasks start like this:

```auto
- name: Apache role skipped
  ansible.builtin.debug:
    msg: "The tasks in the Apache role are not being run since the apache variable is not true."
  when: not apache | bool
  tags:
    - apache

- name: Install and configure Apache
  block:

    # ...

  when: apache | bool
  tags:
    - apache

```

Having a tag per role that matches the role name means I can run Ansible for one role against one server like this:

```bash
ansible-playbook all.yml -t apache -l server.example.org 

```

For each host I have a `host_vars/server.example.org` directory and then one config file per role, for example to install Apache on `server.example.org` I create `host_vars/server.example.org/apache.yml` containing:

```yaml
apache: true

```

I did start by having all the host variables in a YAML `hosts.yml` inventory file and then that got too big I created `host_vars/server.example.org/vars.yml` files per server and then when they became too big I switched to one config file per host per role — having one directory per host for variables and one file per role for the role variables currently works for me…

I do set some variables elsewhere, for example I have have a few set at an inventory level in a `hosts.yml` like this (I could have `ssh` set to `true` for all hosts or for a group of hosts here but I don’t):

```yaml
all:
  vars:
    ansible_python_interpreter: /usr/bin/python3
  children:
    bookworm_servers:
      vars:
        apt_distro: bookworm
      hosts:
        server.example.org:
          ansible_host: 192.168.1.1

```

My suggestion would be to pick a way of doing this that makes sense to you, which you understand and which you think others that also need to use the code have a chance of understanding!
