# subset/limit option in play definition (for applying a play to an intersection of host groups)

**URL:** <https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128>\
**Category:** Ansible Project\
**Tags:** vmware, fedora, ansible-project\
**Created:** [December 7, 2012, 4:39pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128 "2012-12-07T16:39:07Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dag\_Wieers](https://avatars.discourse-cdn.com/v4/letter/d/45deac/32.png) [@Dag\_Wieers](https://forum.ansible.com/u/Dag_Wieers)\
**Post date:** [December 7, 2012, 4:39pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/1 "2012-12-07T16:39:07Z")

</div>

First and foremost our inventory script creates \*a lot of\* groups based on CMDB information, including

Then we have:

&nbsp;&nbsp;- appl (application code, points to a team in the company)  
&nbsp;&nbsp;- environment (dev, test, qa, prod)  
&nbsp;&nbsp;- securityclass (dmz, fta)  
&nbsp;&nbsp;- location (dc1, dc2)  
&nbsp;&nbsp;- hardwaretype (vmware, kvm, blade, standalone)  
&nbsp;&nbsp;- status (to-be-provisioned, provisioned, accepted, production, maintenance)

And we have some combined groups:

&nbsp;&nbsp;- location-environment  
&nbsp;&nbsp;- securityclass-environment

This is mostly based on the need to have variables specific to any of these combinations, or the specific use we have to limit on the command line.

What you can do then is something like:

&nbsp;&nbsp;&nbsp;hosts: webservers:!redhat:!fedora

Which means all the webservers, except the redhat and fedora servers. Which is in set theory the complement. You can make unions too:

&nbsp;&nbsp;&nbsp;hosts: debian:fedora

But what is missing is an intersection option, like (made-up syntax):

&nbsp;&nbsp;&nbsp;hosts: webservers#debian

My preference is to implement union, intersection and complement from set theory and create a syntax for priority rules, etc...

---

<div class="post-metadata">

**Author:** ![Michael\_Liddle](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Michael\_Liddle](https://forum.ansible.com/u/Michael_Liddle)\
**Post date:** [December 7, 2012, 5:01pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/2 "2012-12-07T17:01:02Z")

</div>

E.g.:

hosts: webservers#(debian:london)

hosts: (webservers#debian):london

?

---

<div class="post-metadata">

**Author:** ![Dylan\_Martin](https://avatars.discourse-cdn.com/v4/letter/d/8797f3/32.png) [@Dylan\_Martin](https://forum.ansible.com/u/Dylan_Martin)\
**Post date:** [December 7, 2012, 5:27pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/3 "2012-12-07T17:27:39Z")

</div>

Speaking personally, I’d like to see as much consistency and predictability as possible.

This might be crazy or stupid, so please be gentle when telling me off, but I’d like it if you could do everything from the command line and a play file. Not sure how you would represent all the levels of a yaml file on a cmd line, but I keep getting confused by things that can be set one place but not another. EG --connection works on cmd line but not playbook and hosts: works in playbook but you use --limit on cmd line.

Maybe something like

ansible-playbook --hosts webservers --connection ssh —tasks ----name wheeee ----command “echo this is nuts” an\_almost\_empty\_playbook.yaml

It wouldn’t be all that useful in itself, but it would give us a consistency that would be really powerful (and I suspect easier to code in the long run).

Okay, you may now throw tomatoes at me.

-Dylan

---

<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:** [December 7, 2012, 6:00pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/4 "2012-12-07T18:00:18Z")

</div>

This syntax runs counter to my sensibilities and will not happen.

---

<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:** [December 7, 2012, 6:01pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/5 "2012-12-07T18:01:44Z")

</div>

You can generally do most of these things through feeding variables in  
through --extra-vars.

This prevents bloating the command line options.

I'm generally NOT in favor of supporting this as it discourages reuse  
and recording what you want to do, and doesn't make any sense when  
describing multi-tier operations.

---

<div class="post-metadata">

**Author:** ![Dag\_Wieers](https://avatars.discourse-cdn.com/v4/letter/d/45deac/32.png) [@Dag\_Wieers](https://forum.ansible.com/u/Dag_Wieers)\
**Post date:** [December 7, 2012, 11:57pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/6 "2012-12-07T23:57:40Z")

</div>

Don't dismiss based on syntax only, being able to do the above is very powerful and avoids having to make groups just to be able to set a limit. The fact we don't have the set theory symbols makes it harder to come up with an acceptable syntax that people understand out of the box.

The current syntax Ansible is using today:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;':' means union  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;':!' means intersection (with complement)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'!' means complement

whereas:

&nbsp;&nbsp;- there are no priority rules (left-to-right only ?)  
&nbsp;&nbsp;- union+complement symbols means intersection of complement  
&nbsp;&nbsp;&nbsp;&nbsp;(contrary to what one would expect)  
&nbsp;&nbsp;- one cannot do everything that's useful

There are other symbols to be used.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'&' meaning union  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'|' meaning intersection  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'^' meaning complement

This would avoid the old convention (so we could have backward compatibility) and it might look more readable:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts: (webservers|production|dmz) -\> all webservers in production and in dmz  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts: (webservers&proxyservers)|^production -\> all webservers and proxyservers that are not in production  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts: webservers|(debian&ubuntu) -\> all webservers running debian and ubuntu  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts: webservers|^dbserver -\> all webservers not running a database  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hosts: (blade&standalone)|(rhel&fedora) -\> all physical boxes running RHEL and Fedora

Would that be more acceptable ?

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [December 8, 2012, 3:12am UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/7 "2012-12-08T03:12:21Z")

</div>

This would rock, I currently use extravars to set host for most of my playbooks, this is much more elegant.

Brian Coca

---

<div class="post-metadata">

**Author:** ![Ahmad\_Khayyat](https://avatars.discourse-cdn.com/v4/letter/a/858c86/32.png) [@Ahmad\_Khayyat](https://forum.ansible.com/u/Ahmad_Khayyat)\
**Post date:** [December 8, 2012, 5:43am UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/8 "2012-12-08T05:43:49Z")

</div>

I vote in favor, if anyone’s vote counts.  
However, I’d like to note that ‘&’ is usually used to express ‘and’, which is closer to intersection (present in both operands), while ‘|’ is usually used to express ‘or’, which is closer to union (present in either operand).

So, I propose a modified version:

‘&’ intersecion (present in both)  
‘|’ union (present in either)  
‘^’ complement (not present)

I also second the call for making the feature available both in playbooks and the command line. Perhaps by accepting this syntax in the --limit argument. This leaves variables. Would there be a way to set variables based on such constructs?

Note also that Dag’s proposal involves another operator: grouping using ‘( )’ to control precedence.

That Would be Real Powerful, and would solve a LOT of problems _trivially_.

---

<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:** [December 8, 2012, 3:48pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/9 "2012-12-08T15:48:57Z")

</div>

While I agree that set theory operations sound powerful, we are  
required to add things in ways that don't break existing usage, and  
don't seem redundant or different. Thus if --limit has to continue  
to work the way it works now, and does hosts, I don't want another  
syntax that feels completely different in ways where you have to be  
able to read both. That's a mess.

When I created Ansible, I desired it to not be a programming language,  
and to be maximally auditable. As such, I don't feel that having  
stuff like:

hosts: ((webservers|dbservers)&production

is particularly readable or something I want to encourage, especially  
when existing systems of host specs are intentionally simpler.

The way this is best handled, in my opinion, is maintaining a seperate  
inventory file for your environments, such that inventory for  
production and inventory for stage/development is kept seperate, and  
then it's not a function of --limit at all.

I'd prefer if we had this conversation first in terms of concrete real  
world use cases, and discussed how they could be modelled, rather than  
first saying "here's a language feature I want" and adding it.

---

<div class="post-metadata">

**Author:** ![Ashley\_Penney](https://avatars.discourse-cdn.com/v4/letter/a/48db29/32.png) [@Ashley\_Penney](https://forum.ansible.com/u/Ashley_Penney)\
**Post date:** [December 8, 2012, 6:12pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/10 "2012-12-08T18:12:01Z")

</div>

Maybe I misunderstand how things work but this seems to assume you're  
primarily using static inventory files. I'm trying to use ec2.py right now  
as my inventory script and I want to be able to the following:

tag\_Group\_webservers AND tag\_environment\_production  
tag\_Group\_webservers AND NOT tag\_environment\_production  
tag\_Group\_webservers AND tag\_environment\_production AND tag\_variant\_test

There's some examples where I feel it's impractical to generate dozens of  
inventory files to pick and choose from. Maybe I've misunderstood exactly  
how things work today but this seems difficult to do as things stand. With  
auto scaling groups it's not very practical to do anything but real time  
inventory discovery.

I just wanted to get some real use cases in to make sure I understand what  
we're talking about here.

---

<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:** [December 8, 2012, 11:13pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/11 "2012-12-08T23:13:27Z")

</div>

So if you're using external sources, you could have scripts that keep  
your environments seperate by using seperate config files -- you  
wouldn't have to follow exactly what the included EC2 example does.

That all being said my point is the syntax we have established for  
hosts and limit needs to continue to work, and this means not  
introducing additional newness into it without a way that you are  
using the newness, and I'd like to first understand a use case where  
the newness is required, so we design appropriately.

This could mean a new "hosts\_set:" directive incompatible with the  
latter, but I don't like if it doesn't also answer ways to use it with  
the existing CLI options.

This might mean "set(...)" as some way of designating the newness,  
etc, but I'd like to craft ideas first most around use cases that  
\*can't\* be solved today -- far before we fit an implementation to it  
-- and only then, if we need it.

> Maybe I misunderstand how things work but this seems to assume you're  
> primarily using static inventory files. I'm trying to use ec2.py right now  
> as my inventory script and I want to be able to the following:
> 
> tag\_Group\_webservers AND tag\_environment\_production

hosts: webservers  
limit: production

> tag\_Group\_webservers AND NOT tag\_environment\_production

hosts: webservers  
limit: !production

> tag\_Group\_webservers AND tag\_environment\_production AND tag\_variant\_test

I think this is the sticky one.

Currently "hosts" says, "be in one of these groups, and explicitly NOT  
in any negated groups"

limit says "in addition to what hosts says, it must also be matched by  
something in the limit"

It seems in this case, the proper way to do it in existing ansible  
would be to have a production\_test flag that selected those systems.  
Maybe.

---

<div class="post-metadata">

**Author:** ![Michael\_Liddle](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Michael\_Liddle](https://forum.ansible.com/u/Michael_Liddle)\
**Post date:** [December 10, 2012, 1:52pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/12 "2012-12-10T13:52:54Z")

</div>

If one wanted to go in the direction of adding intersection to the pattern syntax, without making it too complicated, an alternative that retains the current operators and (basic) semantics could be as follows:

‘:’ = ‘add hosts in the following group to the current set’ (union, as current)  
‘:!’ = ‘remove hosts in the the following group from the current set’ (complement, as current)  
‘:!!’ = ‘remove hosts _not_ in the following group from the current set’ (intersection, new)

These patterns could have left-to-right precedence and be read as a simple list of “set building instructions” (i.e. not a complex set-theoretic equation). E.g.

webservers:!!debian

Can be read as:

1. take all hosts in webservers
2. remove hosts not in debian

I’m not sure that every possible combination can be built this way (although maybe they can?), but it certainly adds a few more options and is simpler than having a fully blown expression language.

Whether that pattern _looks_ like it should do that is a different question, I guess!

---

<div class="post-metadata">

**Author:** ![Michael\_Liddle](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Michael\_Liddle](https://forum.ansible.com/u/Michael_Liddle)\
**Post date:** [December 10, 2012, 1:58pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/13 "2012-12-10T13:58:49Z")

</div>

To add my two-cents to this one too… This could work:

hosts: webservers  
limit:

- production
- test

I.e. in play objects limit params can be lists, which would be combined using intersection rules.

From the implementation side this is not a lot different to having to combine a CLI --limit and single play object limit param.

---

<div class="post-metadata">

**Author:** ![Daniel\_Hokka\_Zakriss](https://avatars.discourse-cdn.com/v4/letter/d/f05b48/32.png) [@Daniel\_Hokka\_Zakriss](https://forum.ansible.com/u/Daniel_Hokka_Zakriss)\
**Post date:** [December 10, 2012, 2:28pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/14 "2012-12-10T14:28:22Z")

</div>

Michael DeHaan wrote:

> So if you're using external sources, you could have scripts that keep  
> your environments seperate by using seperate config files -- you  
> wouldn't have to follow exactly what the included EC2 example does.
> 
> That all being said my point is the syntax we have established for  
> hosts and limit needs to continue to work, and this means not  
> introducing additional newness into it without a way that you are  
> using the newness, and I'd like to first understand a use case where  
> the newness is required, so we design appropriately.
> 
> This could mean a new "hosts\_set:" directive incompatible with the  
> latter, but I don't like if it doesn't also answer ways to use it with  
> the existing CLI options.
> 
> This might mean "set(...)" as some way of designating the newness,  
> etc, but I'd like to craft ideas first most around use cases that  
> \*can't\* be solved today -- far before we fit an implementation to it  
> -- and only then, if we need it.

So when we had talked about this before, we had discussed simply extending  
the hosts: (and ansible target) to accept &group to limit to perform the  
intersection. E.g. webservers:!debian:&datacenter1 to limit it to webservers  
not running Debian in datacenter1. This would be rather easy to implement,  
looks like the hosts declaration already does, and allows expressing most of  
the common scenarios.

Adding a limit on the play seems odd and doesn't quite fit with everything  
else.

Daniel

---

<div class="post-metadata">

**Author:** ![Daniel\_Hokka\_Zakriss](https://avatars.discourse-cdn.com/v4/letter/d/f05b48/32.png) [@Daniel\_Hokka\_Zakriss](https://forum.ansible.com/u/Daniel_Hokka_Zakriss)\
**Post date:** [December 10, 2012, 2:58pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/15 "2012-12-10T14:58:39Z")

</div>

Daniel Hokka Zakrisson wrote:

> Michael DeHaan wrote:
> 
> > So if you're using external sources, you could have scripts that keep  
> > your environments seperate by using seperate config files -- you  
> > wouldn't have to follow exactly what the included EC2 example does.
> > 
> > That all being said my point is the syntax we have established for  
> > hosts and limit needs to continue to work, and this means not  
> > introducing additional newness into it without a way that you are  
> > using the newness, and I'd like to first understand a use case where  
> > the newness is required, so we design appropriately.
> > 
> > This could mean a new "hosts\_set:" directive incompatible with the  
> > latter, but I don't like if it doesn't also answer ways to use it with  
> > the existing CLI options.
> > 
> > This might mean "set(...)" as some way of designating the newness,  
> > etc, but I'd like to craft ideas first most around use cases that  
> > \*can't\* be solved today -- far before we fit an implementation to it  
> > -- and only then, if we need it.
> 
> So when we had talked about this before, we had discussed simply extending  
> the hosts: (and ansible target) to accept &group to limit to perform the  
> intersection. E.g. webservers:!debian:&datacenter1 to limit it to  
> webservers  
> not running Debian in datacenter1. This would be rather easy to implement,  
> looks like the hosts declaration already does, and allows expressing most  
> of  
> the common scenarios.

([https://github.com/dhozac/ansible/commit/246472951cb8221aeaf5fc8b5b717909ccb3575a](https://github.com/dhozac/ansible/commit/246472951cb8221aeaf5fc8b5b717909ccb3575a)  
implements this.)

Daniel

---

<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:** [December 10, 2012, 11:34pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/16 "2012-12-10T23:34:30Z")

</div>

> So when we had talked about this before, we had discussed simply extending  
> the hosts: (and ansible target) to accept &group to limit to perform the  
> intersection. E.g. webservers:!debian:&datacenter1 to limit it to webservers  
> not running Debian in datacenter1. This would be rather easy to implement,  
> looks like the hosts declaration already does, and allows expressing most of  
> the common scenarios.

I like this syntax very much.

Great job at simplifying requirements.

--Michael

---

<div class="post-metadata">

**Author:** ![Daniel\_Hokka\_Zakriss](https://avatars.discourse-cdn.com/v4/letter/d/f05b48/32.png) [@Daniel\_Hokka\_Zakriss](https://forum.ansible.com/u/Daniel_Hokka_Zakriss)\
**Post date:** [December 10, 2012, 11:43pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/17 "2012-12-10T23:43:33Z")

</div>

Michael DeHaan wrote:

> > So when we had talked about this before, we had discussed simply  
> > extending  
> > the hosts: (and ansible target) to accept &group to limit to perform the  
> > intersection. E.g. webservers:!debian:&datacenter1 to limit it to  
> > webservers  
> > not running Debian in datacenter1. This would be rather easy to  
> > implement,  
> > looks like the hosts declaration already does, and allows expressing  
> > most of  
> > the common scenarios.
> 
> I like this syntax very much.

I figured you might, it's your original suggestion 😉

Daniel

---

<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:** [December 10, 2012, 11:52pm UTC](https://forum.ansible.com/t/subset-limit-option-in-play-definition-for-applying-a-play-to-an-intersection-of-host-groups/12128/18 "2012-12-10T23:52:35Z")

</div>

> I figured you might, it's your original suggestion 😉
> 
> Daniel

Was it?

You should not tell me these things, as I forget them quickly.

--Michael
