#!/usr/bin/python

import argparse
import json
import yaml
import sys
import os.path

def get(d, key, default):
    if key in d:
        return d[key]
    else:
        return default

def get_in(d, keys, default):
    for key in keys:
        if key in d:
            d = d[key]
        else:
            return default
    return d

# Pointless..
#def assoc(d, key, value):
#    d[key] = value

def assoc_in(d, keys, value):
    for key in keys[:-1]:
        if key not in d:
            d[key] = dict()
        d = d[key]

    d[keys[-1]] = value

def update_in(d, keys, update_fn):
    value = get_in(d, keys, dict())
    assoc_in(d, keys, update_fn(value))

def update(d, key, update_fn):
    d[key] = update_fn(get(d, key, dict()))

def process_hosts(groups, data):
    for host_name, data_host in get(data, "hosts", dict()).iteritems():
        if "vars" in data_host:
            host_vars = get_in(groups, [host_name, "vars"], dict())
            host_vars.update(data_host["vars"])
            assoc_in(groups, [host_name, "vars"], host_vars)
            assoc_in(groups, ["_meta", "hostvars", host_name], host_vars)

        for group_name in get(data_host, "groups", list()):
            group_hosts = get_in(groups, [group_name, "hosts"], list())
            group_hosts.append(host_name)
            assoc_in(groups, [group_name, "hosts"], group_hosts)

    return groups

def process_groups(groups, data):
    #print(json.dumps(groups))
    for group_name, data_group in get(data, "groups", dict()).iteritems():
        group_hosts = get_in(groups, [group_name, "hosts"], list())
        group_vars = get_in(groups, [group_name, "vars"], dict())

        if "hosts" in data_group:
            group_hosts += data_group["hosts"]

        if "vars" in data_group:
            group_vars.update(get(data_group, "vars", dict()))

        if ("include" in data_group):
            for include_name in get(data_group, "include", list()):
                group_hosts += get_in(groups, [include_name, "hosts"], list())

        if "require" in data_group:
            for require_name in get(data_group, "require", list()):
                group_hosts += get_in(groups, [require_name, "hosts"], list())

        if "exclude" in data_group:
            for exclude_name in get(data_group, "require", list()):
                exclude_hosts = get_in(groups, [exclude_name, "hosts"], list())
                group_hosts[:] = [host_name for host_name in group_hosts if host_name not in exclude_hosts]

        if len(group_hosts) > 0:
            assoc_in(groups, [group_name, "hosts"], group_hosts)

        if len(group_vars) > 0:
            assoc_in(groups, [group_name, "vars"], group_vars)

    return groups

def make_groups(data):
    groups = dict()
    meta = dict()
    groups["_meta"] = meta

    process_hosts(groups, data)
    process_groups(groups, data)

    for group_name, group in groups.iteritems():
        update(group, "hosts", lambda hosts: sorted(set(hosts)))

    meta.pop("hosts")
    return groups

def output_list_inventory(data):
    '''
    Output the --list data structure as JSON
    '''
    print json.dumps(make_groups(data))

def find_host(data, host_name):
    '''
    Find the given variables for the given host and output them as JSON
    '''

    print json.dumps(get_in(data, ["hosts", host_name, "vars"], dict()))

def main():
    '''
    Output dynamic inventory as JSON from statically defined data structures
    '''

    # Argument parsing
    parser = argparse.ArgumentParser(description="Ansible dynamic inventory")
    parser.add_argument("--list", help="Ansible inventory of all of the groups",
                        action="store_true", dest="list_inventory")
    parser.add_argument("--host", help="Ansible inventory of a particular host", action="store",
                        dest="ansible_host", type=str)

    cli_args = parser.parse_args()
    list_inventory = cli_args.list_inventory
    ansible_host = cli_args.ansible_host

    data = yaml.load(sys.stdin)

    if list_inventory:
        output_list_inventory(data)

    if ansible_host:
        find_host(data, ansible_host)


if __name__ == "__main__":
    main()

@@ -66,23 +66,8 @@
  sys
-%0Aimport os.path
 %0A%0Ade
@@ -951,16 +951,20 @@
 .update(
+get(
 data_hos
@@ -968,16 +968,25 @@
 host
-%5B
+, 
 %22vars%22
-%5D
+, dict())
 )%0A  
@@ -1657,46 +1657,8 @@
 ))%0A%0A
-        if %22hosts%22 in data_group:%0A    
     
@@ -1676,16 +1676,20 @@
 osts += 
+get(
 data_gro
@@ -1694,56 +1694,28 @@
 roup
-%5B
+, 
 %22hosts%22
-%5D%0A%0A        if %22vars%22 in data_group:%0A    
+, list())%0A%0A
     
@@ -1774,50 +1774,8 @@
 ))%0A%0A
-        if (%22include%22 in data_group):%0A    
     
@@ -1838,36 +1838,32 @@
 )):%0A            
-  
-  
 group_hosts += g
@@ -1914,48 +1914,8 @@
 ))%0A%0A
-        if %22require%22 in data_group:%0A    
     
@@ -1986,33 +1986,30 @@
         
-    group
+require
 _hosts 
-+
 = get_in
@@ -2050,25 +2050,28 @@
 list())%0A
-%0A
+    
         
 if %22excl
@@ -2066,40 +2066,97 @@
     
-if %22exclude%22 in data_group:%0A    
+group_hosts%5B:%5D = %5Bhost_name for host_name in group_hosts if host_name in require_hosts%5D%0A%0A
     
@@ -2188,38 +2188,38 @@
 et(data_group, %22
-requir
+exclud
 e%22, list()):%0A   
@@ -2207,36 +2207,32 @@
 lude%22, list()):%0A
-    
             excl
@@ -2283,36 +2283,32 @@
 osts%22%5D, list())%0A
-    
             grou

Fix require and exclude