Repository: ansible/ansible

Issue:
pause in loop_control not working with templating
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
loop_control -> pause

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.1.0
```

##### CONFIGURATION
<!---
n/a
-->

##### OS / ENVIRONMENT
<!---
n/a
-->

##### SUMMARY
When using pause inside loop_control, it won't accept my float-casted variable.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---
- hosts: localhost
  vars:
    my_var: 20
    something: true
    my_items:
      - hello
      - world
  tasks:
    - block:
        - debug:
            var: my_var
        - debug:
            msg: "Hurray! {{ outer_item }}"
          with_items:
            - "{{ my_items }}"
          loop_control:
            loop_var: outer_item
            pause: my_var | float
```

Also tried variants like:
```
pause: my_var
pause: "{{ my_var | float }}"
pause: my_var | int
pause: "{{ my_var | int }}"
```

To no avail, the error remains the same.

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
I expect a pause of `my_var` seconds.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
PLAY [localhost] ***************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "my_var": 20
}

TASK [debug] *******************************************************************
ok: [localhost] => (item=hello) => {
    "msg": "Hurray! hello",
    "outer_item": "hello"
}
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: a float is required
fatal: [localhost]: FAILED! => {"failed": true, "msg": "Unexpected failure during module execution.", "stdout": ""}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1
```



Discussion:
This playbook works if I replace the variable in pause with a value like: `pause: 10`. So templating does not work.
Noticeable curiosities:

- When the task is skipped, it will still pause once.
- It provides no output of the pause itself (so the user is left wondering).
pause affects first iteration, conditional for skipping does not get evaluated until after pause.
cc @tbielawa
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -16,7 +16,7 @@
 from ansible.executor.task_result import TaskResult
 from ansible.module_utils.six import iteritems, string_types, binary_type
 from ansible.module_utils.six.moves import cPickle
-from ansible.module_utils._text import to_text
+from ansible.module_utils._text import to_text, to_native
 from ansible.playbook.conditional import Conditional
 from ansible.playbook.task import Task
 from ansible.template import Templar
@@ -272,12 +272,15 @@ def _run_loop(self, items):
         index_var = None
         label = None
         loop_pause = 0
+        templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
         if self._task.loop_control:
-            loop_var = self._task.loop_control.loop_var
-            index_var = self._task.loop_control.index_var
-            loop_pause = self._task.loop_control.pause
+            # FIXME: move this to the object itself to allow post_validate to take care of templating
+            loop_var = templar.template(self._task.loop_control.loop_var)
+            index_var = templar.template(self._task.loop_control.index_var)
+            loop_pause = templar.template(self._task.loop_control.pause)
             # the these may be 'None', so we still need to default to something useful
-            label = self._task.loop_control.label or ('{{' + loop_var + '}}')
+            # this is tempalted below after an item is assigned
+            label = (self._task.loop_control.label or ('{{' + loop_var + '}}'))
 
         if loop_var in task_vars:
             display.warning(u"The loop variable '%s' is already in use. "
@@ -296,7 +299,10 @@ def _run_loop(self, items):
 
             # pause between loop iterations
             if loop_pause and ran_once:
-                time.sleep(loop_pause)
+                try:
+                    time.sleep(float(loop_pause))
+                except ValueError as e:
+                    raise AnsibleError('Invalid pause value: %s, produced error: %s' % (loop_pause, to_native(e)))
             else:
                 ran_once = True
 
@@ -326,7 +332,6 @@ def _run_loop(self, items):
             res['_ansible_ignore_errors'] = task_fields.get('ignore_errors')
 
             if label is not None:
-                templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
                 res['_ansible_item_label'] = templar.template(label)
 
             self._rslt_q.put(
@@ -402,7 +407,7 @@ def _squash_items(self, items, loop_var, variables):
                     # * lists can be squashed together
                     # * dicts could squash entries that match in all cases except the
                     #   name or pkg field.
-        except:
+        except Exception:
             # Squashing is an optimization.  If it fails for any reason,
             # simply use the unoptimized list of items.
 
diff --git a/lib/ansible/playbook/loop_control.py b/lib/ansible/playbook/loop_control.py
--- a/lib/ansible/playbook/loop_control.py
+++ b/lib/ansible/playbook/loop_control.py
@@ -23,6 +23,7 @@
 from ansible.playbook.base import Base
 
 
+# FIXME: loopcontrol should not inherit attributes from base, just uses it for load
 class LoopControl(Base):
 
     _loop_var = FieldAttribute(isa='str', default='item')


Test patch: