Limiting hosts when including playbooks

When including a playbook in another playbook, is there any way to limit the hosts in the child playbook?

For example, if I had an existing playbook (e.g., “configure-widget.yaml”) that had its hosts set to “webservers”, and I wanted to write a playbook that only applied to the staging web server, is there any way to do something like:

  • include: configure-widget.yaml limit-hosts=staging

Lorin

I think you can try this
https://groups.google.com/forum/#!msg/ansible-project/qfoeqytbRE4/SI58rlzeEwMJ

If you ever need some exception (all in this group except XX) you can use
hosts: group1:!except_this_group

hosts: group1:&mustBeInThisGroup works too now!

That approach works for limiting hosts when calling from the command-line, but I’d like to do it from inside of a playbook. One of the motivations is what Michael suggests in that original posting:

“The same as the above example could be used with --limit stage or --limit production to control inventory. I really don’t recommend this though, because leaving off limit would be pretty dangerous.”

If I want to limit execution of a playbook to staging servers, I worry about somebody forgetting the “–limit” flag. I’d prefer to do have a separate playbook, say “update-staging.yaml”, that looks like this:

  • include: update.yaml hosts=staging

Lorin Hochstein wrote:

That approach works for limiting hosts when calling from the command-line,
but I'd like to do it from inside of a playbook. One of the motivations is
what Michael suggests in that original posting:

"The same as the above example could be used with --limit stage or --limit
production to control inventory. I really don't recommend this though,
because leaving off limit would be pretty dangerous."

If I want to limit execution of a playbook to staging servers, I worry
about somebody forgetting the "--limit" flag. I'd prefer to do have a
separate playbook, say "update-staging.yaml", that looks like this:

- include: update.yaml hosts=staging

Unfortunately, that doesn't work. Right now I'm using a makefile to invoke
my ansible playbooks to achieve this functionality, but I find that
un-ansible-ish.

Michael, would you accept merges that implemented this sort of host
filtering on include statements? Would work the same as --limit on the
command-line except it would be an argument to include.

hosts: is already templateable with include arguments, so you could do
hosts: webservers:&$hosts
I think this will also lead to an error if you don't specify hosts, instead
of running against all of it.

Daniel

Lorin Hochstein wrote:
> That approach works for limiting hosts when calling from the
command-line,
> but I'd like to do it from inside of a playbook. One of the motivations
is
> what Michael suggests in that original posting:
>
> "The same as the above example could be used with --limit stage or
--limit
> production to control inventory. I really don't recommend this though,
> because leaving off limit would be pretty dangerous."
>
> If I want to limit execution of a playbook to staging servers, I worry
> about somebody forgetting the "--limit" flag. I'd prefer to do have a
> separate playbook, say "update-staging.yaml", that looks like this:
>
> - include: update.yaml hosts=staging
>
> Unfortunately, that doesn't work. Right now I'm using a makefile to
invoke
> my ansible playbooks to achieve this functionality, but I find that
> un-ansible-ish.
>
> Michael, would you accept merges that implemented this sort of host
> filtering on include statements? Would work the same as --limit on the
> command-line except it would be an argument to include.

hosts: is already templateable with include arguments, so you could do
hosts: webservers:&$hosts
I think this will also lead to an error if you don't specify hosts, instead
of running against all of it.

Cool, that works. For anybody who hits this via google, here's a complete
example:

ping.yaml:

- hosts: webservers:&$hosts
  tasks:
   - name: ping the hosts
     action: ping

pong.yaml:

# Just ping the staging server
- include: ping.yaml hosts=staging

This is a useful pattern, where's a good place to document this?

Lorin

Submitted a doc patch here: https://github.com/ansible/ansible/pull/1956

Lorin

(multiple self replies today).

It seems that this doesn’t actually work. The templating on hosts only seems to work against extra_vars that are passed on the command-line, so you can do something like:

ansible-playbook pong.yaml -e hosts=staging

And it will interpolate the “hosts” variable, properly, but if you do:

  • include: ping.yaml hosts=staging

Then the “hosts=staging” part doesn’t get passed in.

I’m not sure if this is a bug, or by design.

Lorin

Templating is a black art, it probably just requires we pass more into
the dictionary for this, and "double template" the include line before
we process it.

Yeah, I’m going to push up a proposed fix into https://github.com/ansible/ansible/pull/1956 shortly.

Lorin

Lorin Hochstein wrote:

Lorin Hochstein wrote:
> That approach works for limiting hosts when calling from the
command-line,
> but I'd like to do it from inside of a playbook.

hosts: is already templateable with include arguments, so you could do

hosts: webservers:&$hosts
I think this will also lead to an error if you don't specify hosts,
instead
of running against all of it.

This is a useful pattern, where's a good place to document this?

Submitted a doc patch here: https://github.com/ansible/ansible/pull/1956

(multiple self replies today).

It seems that this doesn't actually work. The templating on hosts only
seems to work against extra_vars that are passed on the command-line, so
you can do something like:

ansible-playbook pong.yaml -e hosts=staging

And it will interpolate the "hosts" variable, properly, but if you do:

- include: ping.yaml hosts=staging

Then the "hosts=staging" part doesn't get passed in.

I'm not sure if this is a bug, or by design.

This works fine here. Are you on devel, or 0.9? This is new for 1.0, IIRC.

Daniel

I'm on devel: f7e286cf345a97a9ca6b8587cc16fbc901047dc6

I had to do this to get it to work for me:
https://github.com/ansible/ansible/compare/devel...d163c50

Lorin Hochstein wrote:

Lorin Hochstein wrote:
>
>> Lorin Hochstein wrote:
>> >
>> >
>> >>
>> >>
>> >>
>> >>
>> >>>
>> >>>
>> >>>> Lorin Hochstein wrote:
>> >>>> > That approach works for limiting hosts when calling from the
>> >>>> command-line,
>> >>>> > but I'd like to do it from inside of a playbook.
>> >>>>
>> >>>
>> >>
>> >>> hosts: is already templateable with include arguments, so you could
>> do
>> >>>> hosts: webservers:&$hosts
>> >>>> I think this will also lead to an error if you don't specify hosts,
>> >>>> instead
>> >>>> of running against all of it.
>> >>>>
>> >>> This is a useful pattern, where's a good place to document this?
>> >>>
>> >>>
>> >> Submitted a doc patch here:
>> https://github.com/ansible/ansible/pull/1956
>> >>
>> > It seems that this doesn't actually work. The templating on hosts only
>> > seems to work against extra_vars that are passed on the command-line,
>> so
>> > you can do something like:
>> >
>> > ansible-playbook pong.yaml -e hosts=staging
>> >
>> >
>> > And it will interpolate the "hosts" variable, properly, but if you do:
>> >
>> >
>> > - include: ping.yaml hosts=staging
>> >
>> > Then the "hosts=staging" part doesn't get passed in.
>> >
>> >
>> > I'm not sure if this is a bug, or by design.
>>
>> This works fine here. Are you on devel, or 0.9? This is new for 1.0,
>> IIRC.
>>
>>
> I'm on devel: f7e286cf345a97a9ca6b8587cc16fbc901047dc6
>
> I had to do this to get it to work for me:
> https://github.com/ansible/ansible/compare/devel...d163c50

--list-hosts is unfortunately separate and uses different logic to what
would actually be executed. The proper fix here is probably to create the
Play objects and use the same code everywhere.

Oh, it's a list-hosts bug! I just posted #1959, I updated its title to
reflect that the problem is specific to --list-hosts. Definitely good idea
to use the same code path, people will be mighty surprised if --list-hosts
give different output from the actual hosts that are executed.

This is no longer working with the new import_playbook module.

Is there a recommended way to achieve this (i.e. limiting hosts for an imported playbook?). I have not found a way as of yet.

This is not feasbile when the imported playbook is not in one’s own control.
In my use case the imported playbook is a playbook controlled by a third party. The issue here is that the host group names used by that playbook do not necessarily reflect the host names in our inventory.
It would be neat if it were possible to define something like

- import_playbook: playbook
vars:
host_groups:
group1: # this is the host group used in the imported playbook

- our_inv_groupA
- our_inv_groupB

Such functionality would make importing very powerful. I’m not sure if it’s doable with the static nature of importing playbooks, though… I guess it depends on when the inventory comes into play during (pre)processing.

My workaround now is to make sure that the host groups used in the imported playbook exist in our inventory. Further, it has to be ensured that the imported playbook does not use all (since the inventory file may contain other and shared hosts): Can be tested with ``ansible-playbook --list-hosts .

create the groups the imported playbook uses in a group_by in a preceding play

This is amazing!!! Thank you! : )