# Can I couple only\_if and with\_item using a register variable?

**URL:** <https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976>\
**Category:** Ansible Project\
**Created:** [October 13, 2012, 4:45am UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976 "2012-10-13T04:45:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Zack\_Perry](https://avatars.discourse-cdn.com/v4/letter/z/54ee81/32.png) [@Zack\_Perry](https://forum.ansible.com/u/Zack_Perry)\
**Post date:** [October 13, 2012, 4:45am UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/1 "2012-10-13T04:45:27Z")

</div>

I would like to use a playbook like the following to quickly switch a fixed set of virtual machine running one OS to another. But AFAICS, unless I go lower level to libvirt Python binding, I would get errors like the following:

TASK: [Destroy them one by one] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
fatal: [barn0] =\> failed to parse: {“msg”: “Requested operation is not valid: domain is not running”, “failed”: true}  
libvir: QEMU error : Requested operation is not valid: domain is not running

tasks:

- name: Get all existing guest domains, regardless their states  
action: shell …  
register: all\_vm\_names
- name: Get all active guest domains  
action: shell …  
register: active\_vm\_names
- name: Destroy active domains one by one  
action: virt name=$item command=destroy  
**with\_items: ${active\_vm\_names.stdout\_lines}**  
**only\_if: ${active\_vm\_names}**
- name: Undefine all domains one by one  
action: virt name=$item command=undefine  
**with\_items: ${all\_vm\_names.stdout\_lines}**  
**only\_if: ${all\_vm\_names}**

I am using 0.8 devel, and read about the following in CHANGELOG.md:

[…]

- only\_if using register variables that are booleans now works in a boolean way like you’d expect

[…]

I understand for what I would like to do to work, the **only\_if** must have higher precedence than **with\_items**. My sense is that as of now, this is not the case. With YAML being not a programming language, is there a simple way for me to accomplish what I would like to do?

Thanks,

– Zack

---

<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:** [October 13, 2012, 12:23pm UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/2 "2012-10-13T12:23:04Z")

</div>

> I would like to use a playbook like the following to quickly switch a fixed  
> set of virtual machine running one OS to another. But AFAICS, unless I go  
> lower level to libvirt Python binding, I would get errors like the  
> following:
> 
> TASK: [Destroy them one by one] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
> fatal: [barn0] =\> failed to parse: {"msg": "Requested operation is not  
> valid: domain is not running", "failed": true}  
> libvir: QEMU error : Requested operation is not valid: domain is not running
> 
> &nbsp;&nbsp;tasks:  
> &nbsp;&nbsp;&nbsp;&nbsp;- name: Get all existing guest domains, regardless their states  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: shell ...  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;register: all\_vm\_names  
> &nbsp;&nbsp;&nbsp;&nbsp;- name: Get all active guest domains  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: shell ...  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;register: active\_vm\_names  
> &nbsp;&nbsp;&nbsp;&nbsp;- name: Destroy active domains one by one  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: virt name=$item command=destroy  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;with\_items: ${active\_vm\_names.stdout\_lines}  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;only\_if: ${active\_vm\_names}  
> &nbsp;&nbsp;&nbsp;&nbsp;- name: Undefine all domains one by one  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: virt name=$item command=undefine  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;with\_items: ${all\_vm\_names.stdout\_lines}  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;only\_if: ${all\_vm\_names}

Is your intention here to determine if there /are/ any VM names?

all\_vm\_names as you have registered it is a hash and you need to get  
some element out of it. like ${all\_vm\_names.rc} or something.

> I am using 0.8 devel, and read about the following in CHANGELOG.md:
> 
> [...]  
> \* only\_if using register variables that are booleans now works in a boolean  
> way like you'd expect  
> [...]
> 
> I understand for what I would like to do to work, the only\_if must have  
> higher precedence than with\_items. My sense is that as of now, this is not  
> the case.

I don't think it needs to be the case.

with\_items expanding first will expand to multiple task executions,  
but there is a "only\_if" on each expansion.

Though to be honest it seems quite easier to give the virt module a  
command for 'undefine\_all'. That's what I'd do. (Send me a patch?)

---

<div class="post-metadata">

**Author:** ![Zack\_Perry](https://avatars.discourse-cdn.com/v4/letter/z/54ee81/32.png) [@Zack\_Perry](https://forum.ansible.com/u/Zack_Perry)\
**Post date:** [October 13, 2012, 4:49pm UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/3 "2012-10-13T16:49:40Z")

</div>

[...]

> Is your intention here to determine if there /are/ any VM names?

The intention is:

0. Determine whether there are /any/ active domains. Put these into a  
register variable.  
1. Determine /all/ domain names. Put these into another register  
variable.

The reason why I took two steps (and used two register variables) is  
that these domains could assume various states, e.g.

0) defined  
1) shutoff  
2) suspended (aka paused)  
3) running.

Before all these domains can be undefined, it's necessary to destroy  
domains on state 2) and 3) above. Since all guests are of  
"disposable" nature, the brutal 'destroy' command is OK. Without  
this step, libvirt would throw an error if an domains is on state 2.  
or 3, e.g. using the virsh command in shell:

root@barn0:~# virsh undefine ctos0  
error: Failed to undefine domain ctos0  
error: Requested operation is not valid: cannot delete active domain

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> all\_vm\_names as you have registered it is a hash and you need to get  
> some element out of it. like ${all\_vm\_names.rc} or something.

That's my understanding.

[...]

> \> I understand for what I would like to do to work, the only\_if must have  
> \> higher precedence than with\_items. My sense is that as of now, this is not  
> \> the case.
> 
> I don't think it needs to be the case.
> 
> with\_items expanding first will expand to multiple task executions,  
> but there is a "only\_if" on each expansion.

Excellent! Thanks for the tip. I will change my syntax and give it  
another try.

> Though to be honest it seems quite easier to give the virt module a  
> command for 'undefine\_all'. That's what I'd do. (Send me a patch?)

Let me go over the virt module source more. Yes. A 'undefine\_all'  
would be handy.

Regards,

-- Zack

---

<div class="post-metadata">

**Author:** ![Zack\_Perry](https://avatars.discourse-cdn.com/v4/letter/z/54ee81/32.png) [@Zack\_Perry](https://forum.ansible.com/u/Zack_Perry)\
**Post date:** [October 16, 2012, 6:29am UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/4 "2012-10-16T06:29:15Z")

</div>

I got some time tonight to go over the following:

> > tasks:
> > 
> > - name: Get all existing guest domains, regardless their states  
> > action: shell …  
> > register: all\_vm\_names
> > - name: Get all active guest domains  
> > action: shell …  
> > register: active\_vm\_names
> > - name: Destroy active domains one by one  
> > action: virt name=$item command=destroy  
> > with\_items: ${active\_vm\_names.stdout\_lines}  
> > **only\_if: ${active\_vm\_names}**

I changed the above to **only\_if: ${active\_vm\_names.stdout}**

> > - name: Undefine all domains one by one  
> > action: virt name=$item command=undefine  
> > with\_items: ${all\_vm\_names.stdout\_lines}  
> > **only\_if: ${all\_vm\_names}**

ditto: **only\_if: ${all\_vm\_names.stdout}**

If I understand the following statement correctly, then each with\_items task would be executed only if the ${…} is True.

> with\_items expanding first will expand to multiple task executions,  
> but there is a “only\_if” on each expansion.

But, I got the following by running the above with ansible-playbook -vv:

TASK: [Get all existing guest domains, regardless their states, except sl0] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
 REMOTE\_MODULE command … #USE\_SHELL  
changed: [barn0] =\> {“changed”: true, “cmd”: “…”, “delta”: “0:00:00.018831”, “end”: “2012-10-15 23:01:27.838914”, **“rc”: 0** , “start”: “2012-10-15 23:01:27.820083”, **“stderr”: “”, “stdout”: “ctos1\nctos2”** } … **(1)**

TASK: [Get all active guest domains, except sl0] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
 REMOTE\_MODULE command … #USE\_SHELL  
changed: [barn0] =\> {“changed”: true, “cmd”: …, “delta”: “0:00:00.020940”, “end”: “2012-10-15 23:01:27.983329”, **“rc”: 0** , “start”: “2012-10-15 23:01:27.962389”, **“stderr”: “”, “stdout”: “”** } … **(2)**

TASK: [Destroy them one by one] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
fatal: [zettar3] =\> Traceback (most recent call last):  
File “/usr/lib/pymodules/python2.7/ansible/runner/ **init**.py”, line 227, in \_executor  
exec\_rc = self.\_executor\_internal(host)  
File “/usr/lib/pymodules/python2.7/ansible/runner/ **init**.py”, line 276, in \_executor\_internal  
return self.\_executor\_internal\_inner(host, self.module\_name, self.module\_args, inject, port)  
File “/usr/lib/pymodules/python2.7/ansible/runner/ **init**.py”, line 327, in \_executor\_internal\_inner  
if not utils.check\_conditional(conditional):  
File “/usr/lib/pymodules/python2.7/ansible/utils.py”, line 146, in check\_conditional  
return eval(conditional.replace(“\n”, “\n”))  
File “”, line 0

^  
SyntaxError: unexpected EOF while parsing

FATAL: all hosts have already failed – aborting

shell commands in (1) and (2) above have return code (rc) 0, and thus they are constructed correctly for the shell module. The register variable all\_vm\_names’s stdout consists of valid entries. The active\_vm\_names’s stdout is empty, so the task named Destroy active domains one by one shouldn’t execute. But before it gets to that, the core parsing code errored out. Any other suggestion please?

> Though to be honest it seems quite easier to give the virt module a  
> command for ‘undefine\_all’. That’s what I’d do. (Send me a patch?)

I gave this aspect some more deliberation, and came to the conclusion that a undefine\_all is not enough. At least based on our usage, from time to time, we may wish to preserve a few VMs. But so far I don’t have a clean syntax for a list of exceptions. I don’t wish to introduce that pollute ansible’s current overall clean syntax. I will think more…

Regards,

– Zack

---

<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:** [October 16, 2012, 7:45am UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/5 "2012-10-16T07:45:40Z")

</div>

You have to quote variables that are strings. Since variables are substituted (rather than interpreted), so an empty string results in nothing, which is giving you this error.

---

<div class="post-metadata">

**Author:** ![Zack\_Perry](https://avatars.discourse-cdn.com/v4/letter/z/54ee81/32.png) [@Zack\_Perry](https://forum.ansible.com/u/Zack_Perry)\
**Post date:** [October 16, 2012, 3:14pm UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/6 "2012-10-16T15:14:25Z")

</div>

Hi Dag,

Many thanks! Your quoting suggestion did the trick.

> […]
> 
> You have to quote variables that are strings. Since variables are  
> substituted (rather than interpreted), so an empty string results in  
> nothing, which is giving you this error.

> […]

Regards,

– Zack

---

<div class="post-metadata">

**Author:** ![Seth\_Vidal](https://avatars.discourse-cdn.com/v4/letter/s/7ba0ec/32.png) [@Seth\_Vidal](https://forum.ansible.com/u/Seth_Vidal)\
**Post date:** [October 24, 2012, 3:59pm UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/7 "2012-10-24T15:59:27Z")

</div>

Zack,  
&nbsp;&nbsp;I was just catching up on list mail. Are you planning on posting this playbook somewhere when you're done? I've got a similar usecase and if I can implement all of it in a playbook rather than in a script calling ansible as an api then that would be fantastic.

thanks,  
-sv

---

<div class="post-metadata">

**Author:** ![Zack\_Perry](https://avatars.discourse-cdn.com/v4/letter/z/54ee81/32.png) [@Zack\_Perry](https://forum.ansible.com/u/Zack_Perry)\
**Post date:** [October 27, 2012, 1:20am UTC](https://forum.ansible.com/t/can-i-couple-only-if-and-with-item-using-a-register-variable/11976/8 "2012-10-27T01:20:09Z")

</div>

Hi SV,

I will, after polishing it a bit. Yeah, squeezing a bash script into an one liner for the shell module is a bit ugly. Having all such capabilities in a module would be awesome!

Lets do this, with the wiki space that Michael recently made available, I think the playbook example belongs to the wiki at least before you are done with your module. Right now, I am working with Micheal to figure out an annoying and puzzling sudo keyword related bug that I started experiencing since the late stage of 0,8 devel. Am loaded lately, otherwise, I would do more in-depth debugging.

Regards,

– Zack
