Repository: ansible/ansible

Issue:
traceback when using group index on a group without members for a hosts: line
##### Issue Type:

Bug Report
##### Ansible Version:

ansible 1.5 (release1.5.0 6221a2740f) last updated 2014/03/03 12:58:37 (GMT -700)
##### Environment:

N/A
##### Summary:

Using a group index in a hosts: line on a group that does not have any members will create a traceback.
##### Steps To Reproduce:

```

---
- name: Test play 1
  hosts: "global-melange[0]"
  gather_facts: no
  connection: local

  tasks:
    - name: ping
      ping:
```

Followed by a call such as:

```
$ bin/ansible-playbook -i localhost, test.yaml --list-hosts
```
##### Expected Results:

Should get a message saying no hosts found for the play.
##### Actual Results:

```
Traceback (most recent call last):
  File "bin/ansible-playbook", line 308, in <module>
    sys.exit(main(sys.argv[1:]))
  File "bin/ansible-playbook", line 211, in main
    hosts = pb.inventory.list_hosts(play.hosts)
  File "/Users/jkeating/src/ansible/lib/ansible/inventory/__init__.py", line 375, in list_hosts
    result = [ h.name for h in self.get_hosts(pattern) ]
  File "/Users/jkeating/src/ansible/lib/ansible/inventory/__init__.py", line 132, in get_hosts
    hosts = self._get_hosts(patterns)
  File "/Users/jkeating/src/ansible/lib/ansible/inventory/__init__.py", line 177, in _get_hosts
    that = self.__get_hosts(p)
  File "/Users/jkeating/src/ansible/lib/ansible/inventory/__init__.py", line 199, in __get_hosts
    result = self._apply_ranges(pattern, hpat)
  File "/Users/jkeating/src/ansible/lib/ansible/inventory/__init__.py", line 245, in _apply_ranges
    return [ hosts[left] ]
IndexError: list index out of range
```

This was tested using the release1.5.0 branch and devel. I will be working on a patch to correct this.



Discussion:

Resolving patch:
diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py
--- a/lib/ansible/inventory/__init__.py
+++ b/lib/ansible/inventory/__init__.py
@@ -227,6 +227,12 @@ def _apply_ranges(self, pat, hosts):
         given a pattern like foo[0:5], where foo matches hosts, return the first 6 hosts
         """ 
 
+        # If there are no hosts to select from, just return the
+        # empty set. This prevents trying to do selections on an empty set.
+        # issue#6258
+        if not hosts:
+            return hosts
+
         (loose_pattern, limits) = self._enumeration_info(pat)
         if not limits:
             return hosts


Test patch:
diff --git a/test/units/TestInventory.py b/test/units/TestInventory.py
--- a/test/units/TestInventory.py
+++ b/test/units/TestInventory.py
@@ -212,6 +212,11 @@ def test_subset_range(self):
         inventory.subset('greek[0-2];norse[0]')
         self.assertEqual(sorted(inventory.list_hosts()),  sorted(['zeus','hera','thor']))
 
+    def test_subet_range_empty_group(self):
+        inventory = self.simple_inventory()
+        inventory.subset('missing[0]')
+        self.assertEqual(sorted(inventory.list_hosts()), sorted([]))
+
     def test_subset_filename(self):
         inventory = self.simple_inventory()
         inventory.subset('@' + os.path.join(self.test_dir, 'restrict_pattern'))