Repository: ansible/ansible

Issue:
Playbook hosts incorrectly skipped when using --limit flag
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
`ansible-playbook`'s `--limit` flag

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/abed/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.14 (default, Sep 20 2017, 01:25:59) [GCC 7.2.0]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"

Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).

-->
*None*

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
- Arch Linux
- CentOS 7

##### SUMMARY
<!--- Explain the problem briefly -->
`ansible-playbook`'s `--limit` flag fails to select intended hosts in some inventories. An example inventory is provided below.

##### 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.
-->
Run `$ ansible-playbook -i inventory --limit dev-* --list-hosts main.yml` using the following inventory:
```
[dev-tests]
dev-test0
dev-test1
dev-test2

[mongo-replica-set]
dev-mongo0
dev-mongo1
dev-mongo2
```

<!--- Paste example playbooks or commands between quotes below -->
For the sake of completeness, though it is probably not relevant to the issue, this is the playbook I used to produce the inconsistent results.
```yaml
- hosts: all
  tasks:
    - debug:
        msg: a message
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
```
playbook: main.yml

  play #1 (all): test play	TAGS: []
    pattern: [u'all']
    hosts (6):
      dev-test2
      dev-test1
      dev-test0
      dev-mongo2
      dev-mongo1
      dev-mongo0
```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
ansible-playbook 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/abed/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 2.7.14 (default, Sep 20 2017, 01:25:59) [GCC 7.2.0]
Using /etc/ansible/ansible.cfg as config file
setting up inventory plugins
Parsed /home/abed/test/test_inventory inventory source with ini plugin
1 plays in main.yml

playbook: main.yml

  play #1 (all): test play	TAGS: []
    pattern: [u'all']
    hosts (3):
      dev-test2
      dev-test1
      dev-test0
```

If the command is re-run with the argument `dev-m*` instead of `dev-*` (which, in my understanding, is a subset of the original argument) supplied to the `--limit` flag, the following output is produced:
```
playbook: main.yml

  play #1 (all): test play	TAGS: []
    pattern: [u'all']
    hosts (3):
      dev-mongo0
      dev-mongo1
      dev-mongo2
```

This behaviour is inconsistent with the behaviour specified in the docstring of the pattern-matching method [here](https://github.com/ansible/ansible/blob/afc460c9437bad282651609857f73990060ebbc4/lib/ansible/inventory/manager.py#L420-L421).

The issue persists when using the forms `--limit="dev-*"` or `dev*` as well.


Discussion:

Resolving patch:
diff --git a/lib/ansible/inventory/manager.py b/lib/ansible/inventory/manager.py
--- a/lib/ansible/inventory/manager.py
+++ b/lib/ansible/inventory/manager.py
@@ -99,7 +99,7 @@ def split_host_pattern(pattern):
         try:
             (base, port) = parse_address(pattern, allow_ranges=True)
             patterns = [pattern]
-        except:
+        except Exception:
             # The only other case we accept is a ':'-separated list of patterns.
             # This mishandles IPv6 addresses, and is retained only for backwards
             # compatibility.
@@ -526,7 +526,9 @@ def _enumerate_matches(self, pattern):
         if matching_groups:
             for groupname in matching_groups:
                 results.extend(self._inventory.groups[groupname].get_hosts())
-        else:
+
+        # check hosts if no groups matched or it is a regex/glob pattern
+        if not matching_groups or pattern.startswith('~') or any(special in pattern for special in ('.', '?', '*', '[')):
             # pattern might match host
             matching_hosts = self._match_list(self._inventory.hosts, pattern)
             if matching_hosts:


Test patch: