Repository: ansible/ansible

Issue:
with_items and with_random_choice behave differently
##### ISSUE TYPE
 - Bug Report
 - Feature Idea

##### COMPONENT NAME
lookup random_choice

##### ANSIBLE VERSION
```
ansible 2.3.0.0
  config file = /Users/jean0000/evrardjp/ansible-pocs/ansible.cfg
  configured module search path = [u'./plugins/library']
  python version = 2.7.10 (default, Feb  7 2017, 00:08:15) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]
```

Could be on any version.

##### CONFIGURATION

Nothing particularily for reproducing the "bug".

##### OS / ENVIRONMENT
N/A

##### SUMMARY
Expectations problem:
- When running a loop with_items, on an empty list, the task is skipped.
- When running a loop with_random_choice, on an empty list, the task is failed, because the index is out of range (random.choice on an empty list throws an IndexError exception).

##### STEPS TO REPRODUCE

```yaml
---
- hosts: localhost
  gather_facts: no
  connection: local
  vars:
    mylist: ['abc','dev', 'saasas', 'qwqwwqqw']
    mylist2: []
  tasks:
    - name: Expected skip
      debug:
        msg: "{{ item }}"
      with_items: "{{ mylist2 }}"
    - name: Expected random item
      debug:
        msg: "{{ item }}"
      with_items: "{{ mylist | random }}"
    - name: Unexpected failure, not skipping
      debug:
        msg: "{{ item }}"
      with_items: "{{ mylist2 | random }}"
    - name: Unexpected failure, not skipping
      debug:
        msg: "{{ item }}"
      with_random_choice: "{{ mylist2 }}"
#    - name: Very random choice
#      debug:
#        msg: "{{ item }}"
#      with_very_random_choice: "{{ mylist2 }}"

```


##### EXPECTED RESULTS
The task is skipped.

##### ACTUAL RESULTS
Failure
```
PLAYBOOK: random_choice.yml ****************************************************************************************************************************************************************************************************************************************************
1 plays in random_choice.yml

PLAY [localhost] ***************************************************************************************************************************************************************************************************************************************************************
META: ran handlers

TASK [Expected skip] ***********************************************************************************************************************************************************************************************************************************************************
task path: /Users/jean0000/evrardjp/ansible-pocs/random_choice.yml:9

TASK [Expected random item] ****************************************************************************************************************************************************************************************************************************************************
task path: /Users/jean0000/evrardjp/ansible-pocs/random_choice.yml:13
ok: [localhost] => (item=qwqwwqqw) => {
    "item": "qwqwwqqw",
    "msg": "qwqwwqqw"
}

TASK [Unexpected failure, not skipping] ****************************************************************************************************************************************************************************************************************************************
task path: /Users/jean0000/evrardjp/ansible-pocs/random_choice.yml:17
The full traceback is:
Traceback (most recent call last):
  File "/Users/jean0000/.pip-apps/virtualenvs/ansible==2.3/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 89, in run
    items = self._get_loop_items()
  File "/Users/jean0000/.pip-apps/virtualenvs/ansible==2.3/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 214, in _get_loop_items
    items = mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True)
  File "/Users/jean0000/.pip-apps/virtualenvs/ansible==2.3/lib/python2.7/site-packages/ansible/plugins/lookup/random_choice.py", line 38, in run
    return [ random.choice(terms) ]
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.py", line 275, in choice
    return seq[int(self.random() * len(seq))]  # raises IndexError if seq is empty
IndexError: list index out of range

fatal: [localhost]: FAILED! => {
    "failed": true,
    "msg": "Unexpected failure during module execution.",
    "stdout": ""
}
```



Discussion:
Solution: https://gist.github.com/evrardjp/4100215a6970041207519914ca311c81

Resolving patch:
diff --git a/lib/ansible/plugins/lookup/random_choice.py b/lib/ansible/plugins/lookup/random_choice.py
--- a/lib/ansible/plugins/lookup/random_choice.py
+++ b/lib/ansible/plugins/lookup/random_choice.py
@@ -19,6 +19,8 @@
 
 import random
 
+from ansible.errors import AnsibleError
+from ansible.module_utils._text import to_native
 from ansible.plugins.lookup import LookupBase
 
 # useful for introducing chaos ... or just somewhat reasonably fair selection
@@ -36,4 +38,11 @@ class LookupModule(LookupBase):
 
     def run(self, terms, inject=None, **kwargs):
 
-        return [random.choice(terms)]
+        ret = terms
+        if terms:
+            try:
+                ret = [random.choice(terms)]
+            except Exception as e:
+                raise AnsibleError("Unable to choose random term: %s" % to_native(e))
+
+        return ret


Test patch: