Repository: ansible/ansible

Issue:
Order of INI inventory sections causes undefined group vars
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
inventory

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.5.0 (devel 94019e7050) last updated 2017/12/05 11:03:40 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/rteague/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/rteague/git/clusters/aws-c1/ansible/lib/ansible
  executable location = /home/rteague/git/clusters/aws-c1/ansible/bin/ansible
  python version = 2.7.14 (default, Nov  2 2017, 18:42:05) [GCC 7.2.1 20170915 (Red Hat 7.2.1-2)]

```

##### CONFIGURATION
All Ansible config defaults

##### OS / ENVIRONMENT
N/A

##### SUMMARY
<!--- Explain the problem briefly -->
When defining a `[nodes:vars]` section before the `[nodes]` definition, previous group vars are dropped (undefined).  The Ansible docs don't specifically state this order as a requirement and the behavior has changed from 2.3.2 to >=2.4.  Moving the `[nodes:vars]` section after the `[nodes]` section resolves the issue.  Is this an intended 'fix' in Ansible 2.4 or a regression?

##### 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.
-->
Sample inventory: test-inv
```
[OSEv3:children]
masters
nodes

[OSEv3:vars]
deployment_type=openshift-enterprise

[masters]
master[1:3]

[masters:vars]
foo_var=true

[nodes:vars]
foo_var=true

[nodes]
master[1:3]
node[1:3]

```

Test command:
```
$ ansible -i test-inv nodes -m debug -a 'var=deployment_type'
```

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
```
$ ansible --version
ansible 2.3.2.0 (detached HEAD c7052b42c7) last updated 2017/12/05 11:53:37 (GMT -400)
  config file = /home/rteague/git/clusters/aws-c1/ansible.cfg
  configured module search path = [u'/usr/lib/python2.7/site-packages/ara/plugins/modules']
  python version = 2.7.14 (default, Nov  2 2017, 18:42:05) [GCC 7.2.1 20170915 (Red Hat 7.2.1-2)]

$ ansible -i test-inv nodes -m debug -a 'var=deployment_type'
node1 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
node3 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
master3 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
node2 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
master1 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
master2 | SUCCESS => {
    "deployment_type": "openshift-enterprise"
}
```

##### ACTUAL RESULTS
```
$ ansible --version
ansible 2.5.0 (devel 94019e7050) last updated 2017/12/05 11:03:40 (GMT -400)
  config file = /home/rteague/git/clusters/aws-c1/ansible.cfg
  configured module search path = [u'/usr/lib/python2.7/site-packages/ara/plugins/modules']
  ansible python module location = /home/rteague/git/clusters/aws-c1/ansible/lib/ansible
  executable location = /home/rteague/git/clusters/aws-c1/ansible/bin/ansible
  python version = 2.7.14 (default, Nov  2 2017, 18:42:05) [GCC 7.2.1 20170915 (Red Hat 7.2.1-2)]


$ ansible -i test-inv nodes -m debug -a 'var=deployment_type'
master1 | SUCCESS => {
    "changed": false, 
    "deployment_type": "openshift-enterprise"
}
master2 | SUCCESS => {
    "changed": false, 
    "deployment_type": "openshift-enterprise"
}
master3 | SUCCESS => {
    "changed": false, 
    "deployment_type": "openshift-enterprise"
}
node1 | SUCCESS => {
    "changed": false, 
    "deployment_type": "VARIABLE IS NOT DEFINED!"
}
node2 | SUCCESS => {
    "changed": false, 
    "deployment_type": "VARIABLE IS NOT DEFINED!"
}
node3 | SUCCESS => {
    "changed": false, 
    "deployment_type": "VARIABLE IS NOT DEFINED!"
}

```

Related issue: https://bugzilla.redhat.com/show_bug.cgi?id=1520935


Discussion:
Files identified in the description:
* [lib/ansible/inventory](https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Confirmed, this is not expected results. Will look at getting a fix in.

Resolving patch:
diff --git a/lib/ansible/plugins/inventory/ini.py b/lib/ansible/plugins/inventory/ini.py
--- a/lib/ansible/plugins/inventory/ini.py
+++ b/lib/ansible/plugins/inventory/ini.py
@@ -179,7 +179,12 @@ def _parse(self, path, lines):
                     # Either [groupname] or [groupname:children] is sufficient to declare a group,
                     # but [groupname:vars] is allowed only if the # group is declared elsewhere.
                     # We add the group anyway, but make a note in pending_declarations to check at the end.
-                    if state == 'vars':
+                    #
+                    # It's possible that a group is previously pending due to being defined as a child
+                    # group, in that case we simply pass so that the logic below to process pending
+                    # declarations will take the appropriate action for a pending child group instead of
+                    # incorrectly handling it as a var state pending declaration
+                    if state == 'vars' and groupname not in pending_declarations:
                         pending_declarations[groupname] = dict(line=self.lineno, state=state, name=groupname)
 
                     self.inventory.add_group(groupname)


Test patch: