# How to target one host from a list?

**URL:** <https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314>\
**Category:** Ansible Project\
**Created:** [May 23, 2014, 12:51pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314 "2014-05-23T12:51:04Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 23, 2014, 12:51pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/1 "2014-05-23T12:51:04Z")

</div>

We have multiple versions of a multi-tier application deployed on EC2. Each instance is tagged with version and role.

Versions might be clustered (so could be multiple instances with same version and role tag).

For example, we might have:  
2 instances tagged version=1 and role=foo

2 instances tagged version=1 and role=bar

1 instance tagged version=2 and role=foo  
1 instance tagged version=2 and role=bar

We want to use ansible to run a command on one instance of a specified version/role.

What’s the best way to do that?

I tried the following, but seems that the index applies to the individual tag match – not the result of the logical union.

$ ansible “tag\_version\_1:&tag\_role\_foo[0]” -m ping  
No hosts matched

$ ansible “tag\_version\_1:&tag\_role\_foo” -m ping  
10.0.14.123 | success \>\> {  
“changed”: false,  
“ping”: “pong”  
}

Appreciate any advice!

– Steve

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 25, 2014, 2:29am UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/2 "2014-05-25T02:29:32Z")

</div>

Found a brute-force solution:

$ ipaddr=$(ansible "tag\_version\_1:&tag\_role\_foo" --list-hosts | head -n 2 | tail -n 1)  
$ ansible ${ipaddr} -m ping

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 25, 2014, 8:58pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/3 "2014-05-25T20:58:43Z")

</div>

The Ansible way would prefer it simpler.

Here’s how you select the first node out of a group:

- hosts: groupname[0]  
tasks:
- …

Here’s how you select a node that is in two groups:

- hosts: group1:&group2

Here’s how you would select a node that is in two groups and make a group of the union:

- hosts: group1:&group2  
tasks:
- group\_by: key=groupOneAndTwo

Here’s how you would then pick the first host out of that group

- hosts: groupOneAndTwo[0]  
tasks:
- shell: echo I am the first node in both!

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 27, 2014, 10:00pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/4 "2014-05-27T22:00:45Z")

</div>

Much better.

Thanks for the example. Good lesson: Playbooks may contain multiple “hosts”.

Thanks for the help!

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 29, 2014, 4:49pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/5 "2014-05-29T16:49:31Z")

</div>

Michael’s suggestion is working fine in our existing system.

I’ve now hit a bootstrapping problem when applying this to a new system, which results in “list index out of range” error.

We’re automating replacement of servers behind a reverse proxy from one set to another. With each transition, we must execute a command on one of the outgoing servers. Our current playbook works fine when there is an outgoing server – but in a new system, there is no outgoing server on the first run.

Following is the relevant portion of our playbook. When applied on a first run to our new system, “outgoing\_version” is empty. The pattern “group\_:&group2” contains no hosts, so the first task is not run. Not surprisingly, we then hit an error on the second hosts pattern because “outgoing” is not defined.

Is there a proper way to do this with Ansible? Perhaps some way to mark the second play conditional on “outgoing” being defined?

Thanks!

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 29, 2014, 4:57pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/6 "2014-05-29T16:57:42Z")

</div>

Clarification: Our playbook also includes plays for the incoming servers interleaved with plays for the outgoing servers. Hoping to avoid one playbook for only incoming servers – and another for incoming + outgoing servers (would have duplication).

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 29, 2014, 5:44pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/7 "2014-05-29T17:44:44Z")

</div>

Sorry for the spam, but I just stumbled upon a [possible solution](https://groups.google.com/forum/#!topic/ansible-project/eqNR_RdC0jg) that uses Jinja’s “default” filter.

I modified hosts in the second play to default to a list with one item that doesn’t match any of our hosts.

The ‘no-match’ still feels like a hack, but has allowed us to use one playbook for bootstrap (first run) and beyond.

Still appreciate any pointers if there’s a better way 🙂

Thanks.

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 30, 2014, 5:15pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/8 "2014-05-30T17:15:20Z")

</div>

After closer inspection: The posted playbook works for bootstrap (first run), but not beyond.

Seems that “outgoing” is not defined in the Jinja template on the second play, so the default value (‘no-match’) is always used.

Seems that “groups” is also not available in the Jinja template (e.g. groups.outgoing).

Is there a way to access groups within the template (“{{ … }}”) ?

Thanks.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 31, 2014, 4:24pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/9 "2014-05-31T16:24:27Z")

</div>

"- hosts: “{{ outgoing|default([‘no-match’]) }}[0]”

In Ansible, the general rule is if something looks ungainly like this, don’t do it 🙂

I would probably consider having one playbook that includes another list of plays, and running either the top level one or the second one depending on whether you need to do the second step.

Might not work for you to me.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 31, 2014, 4:24pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/10 "2014-05-31T16:24:45Z")

</div>

Last line should be “might not work for your use case”

---

<div class="post-metadata">

**Author:** ![Steve\_Ims](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@Steve\_Ims](https://forum.ansible.com/u/Steve_Ims)\
**Post date:** [May 31, 2014, 4:40pm UTC](https://forum.ansible.com/t/how-to-target-one-host-from-a-list/15314/11 "2014-05-31T16:40:46Z")

</div>

I came to the same conclusion: We have separate playbooks now.

Learned a lot along the way.

Thanks for the comments!
