We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Use Consul DNS instead of .novalocal
Templatizing the hosts file to include `.novalocal` worked when we were only on OpenStack, but now that we have multiple providers we need a better way to do service discovery. Fortunately, we have Consul DNS, which will probably work.
- [ ] change Mesos to use DNS name
- [ ] change Marathon to use DNS name


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plugins/inventory/terraform.py`
Content:
```
1 #!/usr/bin/env python
2 """\
3 Dynamic inventory for Terraform - finds all `.tfstate` files below the working
4 directory and generates an inventory based on them.
5 """
6 from __future__ import unicode_literals, print_function
7 import argparse
8 from collections import defaultdict
9 from functools import wraps
10 import json
11 import os
12 import re
13 
14 
15 def tfstates(root=None):
16     root = root or os.getcwd()
17     for dirpath, _, filenames in os.walk(root):
18         for name in filenames:
19             if os.path.splitext(name)[-1] == '.tfstate':
20                 yield os.path.join(dirpath, name)
21 
22 
23 def iterresources(filenames):
24     for filename in filenames:
25         with open(filename, 'r') as json_file:
26             state = json.load(json_file)
27             for module in state['modules']:
28                 for key, resource in module['resources'].items():
29                     yield key, resource
30 
31 ## READ RESOURCES
32 PARSERS = {}
33 
34 
35 def _clean_dc(dcname):
36     # Consul DCs are strictly alphanumeric with underscores and hyphens -
37     # ensure that the consul_dc attribute meets these requirements.
38     return re.sub('[^\w_\-]', '-', dcname)
39 
40 
41 def iterhosts(resources):
42     '''yield host tuples of (name, attributes, groups)'''
43     for key, resource in resources:
44         resource_type, name = key.split('.', 1)
45         try:
46             parser = PARSERS[resource_type]
47         except KeyError:
48             continue
49 
50         yield parser(resource)
51 
52 
53 def parses(prefix):
54     def inner(func):
55         PARSERS[prefix] = func
56         return func
57 
58     return inner
59 
60 
61 def calculate_mi_vars(func):
62     """calculate microservices-infrastructure vars"""
63 
64     @wraps(func)
65     def inner(*args, **kwargs):
66         name, attrs, groups = func(*args, **kwargs)
67 
68         # attrs
69         if attrs['role'] == 'control':
70             attrs['consul_is_server'] = True
71         elif attrs['role'] == 'worker':
72             attrs['consul_is_server'] = False
73 
74         # groups
75         if attrs.get('publicly_routable', False):
76             groups.append('publicly_routable')
77 
78         return name, attrs, groups
79 
80     return inner
81 
82 
83 def _parse_prefix(source, prefix, sep='.'):
84     for compkey, value in source.items():
85         try:
86             curprefix, rest = compkey.split(sep, 1)
87         except ValueError:
88             continue
89 
90         if curprefix != prefix or rest == '#':
91             continue
92 
93         yield rest, value
94 
95 
96 def parse_attr_list(source, prefix, sep='.'):
97     size_key = '%s%s#' % (prefix, sep)
98     try:
99         size = int(source[size_key])
100     except KeyError:
101         return []
102 
103     attrs = [{} for _ in range(size)]
104     for compkey, value in _parse_prefix(source, prefix, sep):
105         nth, key = compkey.split(sep, 1)
106         attrs[int(nth)][key] = value
107 
108     return attrs
109 
110 
111 def parse_dict(source, prefix, sep='.'):
112     return dict(_parse_prefix(source, prefix, sep))
113 
114 
115 def parse_list(source, prefix, sep='.'):
116     return [value for _, value in _parse_prefix(source, prefix, sep)]
117 
118 
119 @parses('openstack_compute_instance_v2')
120 @calculate_mi_vars
121 def openstack_host(resource, tfvars=None):
122     raw_attrs = resource['primary']['attributes']
123     name = raw_attrs['name']
124     groups = []
125 
126     attrs = {
127         'access_ip_v4': raw_attrs['access_ip_v4'],
128         'access_ip_v6': raw_attrs['access_ip_v6'],
129         'flavor': parse_dict(raw_attrs, 'flavor',
130                              sep='_'),
131         'id': raw_attrs['id'],
132         'image': parse_dict(raw_attrs, 'image',
133                             sep='_'),
134         'key_pair': raw_attrs['key_pair'],
135         'metadata': parse_dict(raw_attrs, 'metadata'),
136         'network': parse_attr_list(raw_attrs, 'network'),
137         'region': raw_attrs['region'],
138         'security_groups': parse_list(raw_attrs, 'security_groups'),
139         #ansible
140         'ansible_ssh_port': 22,
141         'ansible_ssh_user': 'centos',
142     }
143 
144     try:
145         attrs.update({
146             'ansible_ssh_host': raw_attrs['access_ip_v4'],
147             'publicly_routable': True,
148         })
149     except (KeyError, ValueError):
150         attrs.update({'ansible_ssh_host': '', 'publicly_routable': False, })
151 
152     # attrs specific to microservices-infrastructure
153     attrs.update({
154         'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['region'])),
155         'role': attrs['metadata'].get('role', 'none')
156     })
157 
158     # add groups based on attrs
159     groups.append('os_image=' + attrs['image']['name'])
160     groups.append('os_flavor=' + attrs['flavor']['name'])
161     groups.extend('os_metadata_%s=%s' % item
162                   for item in attrs['metadata'].items())
163     groups.append('os_region=' + attrs['region'])
164 
165     # groups specific to microservices-infrastructure
166     groups.append('role=' + attrs['metadata'].get('role', 'none'))
167     groups.append('dc=' + attrs['consul_dc'])
168 
169     return name, attrs, groups
170 
171 
172 @parses('google_compute_instance')
173 @calculate_mi_vars
174 def gce_host(resource, tfvars=None):
175     name = resource['primary']['id']
176     raw_attrs = resource['primary']['attributes']
177     groups = []
178 
179     # network interfaces
180     interfaces = parse_attr_list(raw_attrs, 'network_interface')
181     for interface in interfaces:
182         interface['access_config'] = parse_attr_list(interface,
183                                                      'access_config')
184         for key in interface.keys():
185             if '.' in key:
186                 del interface[key]
187 
188     # general attrs
189     attrs = {
190         'can_ip_forward': raw_attrs['can_ip_forward'] == 'true',
191         'disks': parse_attr_list(raw_attrs, 'disk'),
192         'machine_type': raw_attrs['machine_type'],
193         'metadata': parse_dict(raw_attrs, 'metadata'),
194         'network': parse_attr_list(raw_attrs, 'network'),
195         'network_interface': interfaces,
196         'self_link': raw_attrs['self_link'],
197         'service_account': parse_attr_list(raw_attrs, 'service_account'),
198         'tags': parse_list(raw_attrs, 'tags'),
199         'zone': raw_attrs['zone'],
200         # ansible
201         'ansible_ssh_port': 22,
202         'ansible_ssh_user': 'deploy',
203     }
204 
205     # attrs specific to microservices-infrastructure
206     attrs.update({
207         'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['zone'])),
208         'role': attrs['metadata'].get('role', 'none')
209     })
210 
211     try:
212         attrs.update({
213             'ansible_ssh_host': interfaces[0]['access_config'][0]['nat_ip'],
214             'publicly_routable': True,
215         })
216     except (KeyError, ValueError):
217         attrs.update({'ansible_ssh_host': '', 'publicly_routable': False})
218 
219     # add groups based on attrs
220     groups.extend('gce_image=' + disk['image'] for disk in attrs['disks'])
221     groups.append('gce_machine_type=' + attrs['machine_type'])
222     groups.extend('gce_metadata_%s=%s' % (key, value)
223                   for (key, value) in attrs['metadata'].items()
224                   if key not in set(['sshKeys']))
225     groups.extend('gce_tag=' + tag for tag in attrs['tags'])
226     groups.append('gce_zone=' + attrs['zone'])
227 
228     if attrs['can_ip_forward']:
229         groups.append('gce_ip_forward')
230     if attrs['publicly_routable']:
231         groups.append('gce_publicly_routable')
232 
233     # groups specific to microservices-infrastructure
234     groups.append('role=' + attrs['metadata'].get('role', 'none'))
235     groups.append('dc=' + attrs['consul_dc'])
236 
237     return name, attrs, groups
238 
239 
240 ## QUERY TYPES
241 def query_host(hosts, target):
242     for name, attrs, _ in hosts:
243         if name == target:
244             return attrs
245 
246     return {}
247 
248 
249 def query_list(hosts):
250     groups = defaultdict(dict)
251     meta = {}
252 
253     for name, attrs, hostgroups in hosts:
254         for group in set(hostgroups):
255             groups[group].setdefault('hosts', [])
256             groups[group]['hosts'].append(name)
257 
258         meta[name] = attrs
259 
260     groups['_meta'] = {'hostvars': meta}
261     return groups
262 
263 
264 def main():
265 
266     parser = argparse.ArgumentParser(__file__, __doc__)
267     modes = parser.add_mutually_exclusive_group(required=True)
268     modes.add_argument('--list',
269                        action='store_true',
270                        help='list all variables')
271     modes.add_argument('--host', help='list variables for a single host')
272     parser.add_argument('--pretty',
273                         action='store_true',
274                         help='pretty-print output JSON')
275     parser.add_argument('--nometa',
276                         action='store_true',
277                         help='with --list, exclude hostvars')
278 
279     args = parser.parse_args()
280 
281     hosts = iterhosts(iterresources(tfstates()))
282     if args.list:
283         output = query_list(hosts)
284         if args.nometa:
285             del output['_meta']
286     else:
287         output = query_host(hosts, args.host)
288 
289     print(json.dumps(output, indent=4 if args.pretty else None))
290     parser.exit()
291 
292 
293 if __name__ == '__main__':
294     main()
295
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plugins/inventory/terraform.py b/plugins/inventory/terraform.py
--- a/plugins/inventory/terraform.py
+++ b/plugins/inventory/terraform.py
@@ -116,6 +116,17 @@
     return [value for _, value in _parse_prefix(source, prefix, sep)]
 
 
+def parse_bool(string_form):
+    token = string_form.lower()[0]
+
+    if token == 't':
+        return True
+    elif token == 'f':
+        return False
+    else:
+        raise ValueError('could not convert %r to a bool' % string_form)
+
+
 @parses('openstack_compute_instance_v2')
 @calculate_mi_vars
 def openstack_host(resource, tfvars=None):
@@ -169,6 +180,65 @@
     return name, attrs, groups
 
 
+@parses('aws_instance')
+@calculate_mi_vars
+def aws_host(resource, tfvars=None):
+    name = resource['primary']['attributes']['tags.Name']
+    raw_attrs = resource['primary']['attributes']
+
+    groups = []
+
+    attrs = {
+        'ami': raw_attrs['ami'],
+        'availability_zone': raw_attrs['availability_zone'],
+        'ebs_block_device': parse_attr_list(raw_attrs, 'ebs_block_device'),
+        'ebs_optimized': parse_bool(raw_attrs['ebs_optimized']),
+        'ephemeral_block_device': parse_attr_list(raw_attrs,
+                                                  'ephemeral_block_device'),
+        'id': raw_attrs['id'],
+        'key_name': raw_attrs['key_name'],
+        'private': parse_dict(raw_attrs, 'private',
+                              sep='_'),
+        'public': parse_dict(raw_attrs, 'public',
+                             sep='_'),
+        'root_block_device': parse_attr_list(raw_attrs, 'root_block_device'),
+        'security_groups': parse_attr_list(raw_attrs, 'security_groups'),
+        'subnet': parse_dict(raw_attrs, 'subnet',
+                             sep='_'),
+        'tags': parse_dict(raw_attrs, 'tags'),
+        'tenancy': raw_attrs['tenancy'],
+        'vpc_security_group_ids': parse_list(raw_attrs,
+                                             'vpc_security_group_ids'),
+        # ansible-specific
+        'ansible_ssh_port': 22,
+        'ansible_ssh_user': raw_attrs['tags.sshUser'],
+        'ansible_ssh_host': raw_attrs['public_ip'],
+    }
+
+    # attrs specific to microservices-infrastructure
+    attrs.update({
+        'consul_dc': attrs['tags'].get('dc'),
+        'role': attrs['tags'].get('role', 'none')
+    })
+
+    # groups specific to microservices-infrastructure
+    groups.extend(['aws_ami=' + attrs['ami'],
+                   'aws_az=' + attrs['availability_zone'],
+                   'aws_key_name=' + attrs['key_name'],
+                   'aws_tenancy=' + attrs['tenancy']])
+    groups.extend('aws_tag_%s=%s' % item for item in attrs['tags'].items())
+    groups.extend('aws_vpc_security_group=' + group
+                  for group in attrs['vpc_security_group_ids'])
+    groups.extend('aws_subnet_%s=%s' % subnet
+                  for subnet in attrs['subnet'].items())
+
+    # groups specific to microservices-infrastructure
+    groups.append('role=' + attrs['role'])
+    groups.append('dc=' + attrs['consul_dc'])
+
+    return name, attrs, groups
+
+
 @parses('google_compute_instance')
 @calculate_mi_vars
 def gce_host(resource, tfvars=None):

{"golden_diff": "diff --git a/plugins/inventory/terraform.py b/plugins/inventory/terraform.py\n--- a/plugins/inventory/terraform.py\n+++ b/plugins/inventory/terraform.py\n@@ -116,6 +116,17 @@\n     return [value for _, value in _parse_prefix(source, prefix, sep)]\n \n \n+def parse_bool(string_form):\n+    token = string_form.lower()[0]\n+\n+    if token == 't':\n+        return True\n+    elif token == 'f':\n+        return False\n+    else:\n+        raise ValueError('could not convert %r to a bool' % string_form)\n+\n+\n @parses('openstack_compute_instance_v2')\n @calculate_mi_vars\n def openstack_host(resource, tfvars=None):\n@@ -169,6 +180,65 @@\n     return name, attrs, groups\n \n \n+@parses('aws_instance')\n+@calculate_mi_vars\n+def aws_host(resource, tfvars=None):\n+    name = resource['primary']['attributes']['tags.Name']\n+    raw_attrs = resource['primary']['attributes']\n+\n+    groups = []\n+\n+    attrs = {\n+        'ami': raw_attrs['ami'],\n+        'availability_zone': raw_attrs['availability_zone'],\n+        'ebs_block_device': parse_attr_list(raw_attrs, 'ebs_block_device'),\n+        'ebs_optimized': parse_bool(raw_attrs['ebs_optimized']),\n+        'ephemeral_block_device': parse_attr_list(raw_attrs,\n+                                                  'ephemeral_block_device'),\n+        'id': raw_attrs['id'],\n+        'key_name': raw_attrs['key_name'],\n+        'private': parse_dict(raw_attrs, 'private',\n+                              sep='_'),\n+        'public': parse_dict(raw_attrs, 'public',\n+                             sep='_'),\n+        'root_block_device': parse_attr_list(raw_attrs, 'root_block_device'),\n+        'security_groups': parse_attr_list(raw_attrs, 'security_groups'),\n+        'subnet': parse_dict(raw_attrs, 'subnet',\n+                             sep='_'),\n+        'tags': parse_dict(raw_attrs, 'tags'),\n+        'tenancy': raw_attrs['tenancy'],\n+        'vpc_security_group_ids': parse_list(raw_attrs,\n+                                             'vpc_security_group_ids'),\n+        # ansible-specific\n+        'ansible_ssh_port': 22,\n+        'ansible_ssh_user': raw_attrs['tags.sshUser'],\n+        'ansible_ssh_host': raw_attrs['public_ip'],\n+    }\n+\n+    # attrs specific to microservices-infrastructure\n+    attrs.update({\n+        'consul_dc': attrs['tags'].get('dc'),\n+        'role': attrs['tags'].get('role', 'none')\n+    })\n+\n+    # groups specific to microservices-infrastructure\n+    groups.extend(['aws_ami=' + attrs['ami'],\n+                   'aws_az=' + attrs['availability_zone'],\n+                   'aws_key_name=' + attrs['key_name'],\n+                   'aws_tenancy=' + attrs['tenancy']])\n+    groups.extend('aws_tag_%s=%s' % item for item in attrs['tags'].items())\n+    groups.extend('aws_vpc_security_group=' + group\n+                  for group in attrs['vpc_security_group_ids'])\n+    groups.extend('aws_subnet_%s=%s' % subnet\n+                  for subnet in attrs['subnet'].items())\n+\n+    # groups specific to microservices-infrastructure\n+    groups.append('role=' + attrs['role'])\n+    groups.append('dc=' + attrs['consul_dc'])\n+\n+    return name, attrs, groups\n+\n+\n @parses('google_compute_instance')\n @calculate_mi_vars\n def gce_host(resource, tfvars=None):\n", "issue": "Use Consul DNS instead of .novalocal\nTemplatizing the hosts file to include `.novalocal` worked when we were only on OpenStack, but now that we have multiple providers we need a better way to do service discovery. Fortunately, we have Consul DNS, which will probably work.\n- [ ] change Mesos to use DNS name\n- [ ] change Marathon to use DNS name\n\n", "before_files": [{"content": "#!/usr/bin/env python\n\"\"\"\\\nDynamic inventory for Terraform - finds all `.tfstate` files below the working\ndirectory and generates an inventory based on them.\n\"\"\"\nfrom __future__ import unicode_literals, print_function\nimport argparse\nfrom collections import defaultdict\nfrom functools import wraps\nimport json\nimport os\nimport re\n\n\ndef tfstates(root=None):\n    root = root or os.getcwd()\n    for dirpath, _, filenames in os.walk(root):\n        for name in filenames:\n            if os.path.splitext(name)[-1] == '.tfstate':\n                yield os.path.join(dirpath, name)\n\n\ndef iterresources(filenames):\n    for filename in filenames:\n        with open(filename, 'r') as json_file:\n            state = json.load(json_file)\n            for module in state['modules']:\n                for key, resource in module['resources'].items():\n                    yield key, resource\n\n## READ RESOURCES\nPARSERS = {}\n\n\ndef _clean_dc(dcname):\n    # Consul DCs are strictly alphanumeric with underscores and hyphens -\n    # ensure that the consul_dc attribute meets these requirements.\n    return re.sub('[^\\w_\\-]', '-', dcname)\n\n\ndef iterhosts(resources):\n    '''yield host tuples of (name, attributes, groups)'''\n    for key, resource in resources:\n        resource_type, name = key.split('.', 1)\n        try:\n            parser = PARSERS[resource_type]\n        except KeyError:\n            continue\n\n        yield parser(resource)\n\n\ndef parses(prefix):\n    def inner(func):\n        PARSERS[prefix] = func\n        return func\n\n    return inner\n\n\ndef calculate_mi_vars(func):\n    \"\"\"calculate microservices-infrastructure vars\"\"\"\n\n    @wraps(func)\n    def inner(*args, **kwargs):\n        name, attrs, groups = func(*args, **kwargs)\n\n        # attrs\n        if attrs['role'] == 'control':\n            attrs['consul_is_server'] = True\n        elif attrs['role'] == 'worker':\n            attrs['consul_is_server'] = False\n\n        # groups\n        if attrs.get('publicly_routable', False):\n            groups.append('publicly_routable')\n\n        return name, attrs, groups\n\n    return inner\n\n\ndef _parse_prefix(source, prefix, sep='.'):\n    for compkey, value in source.items():\n        try:\n            curprefix, rest = compkey.split(sep, 1)\n        except ValueError:\n            continue\n\n        if curprefix != prefix or rest == '#':\n            continue\n\n        yield rest, value\n\n\ndef parse_attr_list(source, prefix, sep='.'):\n    size_key = '%s%s#' % (prefix, sep)\n    try:\n        size = int(source[size_key])\n    except KeyError:\n        return []\n\n    attrs = [{} for _ in range(size)]\n    for compkey, value in _parse_prefix(source, prefix, sep):\n        nth, key = compkey.split(sep, 1)\n        attrs[int(nth)][key] = value\n\n    return attrs\n\n\ndef parse_dict(source, prefix, sep='.'):\n    return dict(_parse_prefix(source, prefix, sep))\n\n\ndef parse_list(source, prefix, sep='.'):\n    return [value for _, value in _parse_prefix(source, prefix, sep)]\n\n\n@parses('openstack_compute_instance_v2')\n@calculate_mi_vars\ndef openstack_host(resource, tfvars=None):\n    raw_attrs = resource['primary']['attributes']\n    name = raw_attrs['name']\n    groups = []\n\n    attrs = {\n        'access_ip_v4': raw_attrs['access_ip_v4'],\n        'access_ip_v6': raw_attrs['access_ip_v6'],\n        'flavor': parse_dict(raw_attrs, 'flavor',\n                             sep='_'),\n        'id': raw_attrs['id'],\n        'image': parse_dict(raw_attrs, 'image',\n                            sep='_'),\n        'key_pair': raw_attrs['key_pair'],\n        'metadata': parse_dict(raw_attrs, 'metadata'),\n        'network': parse_attr_list(raw_attrs, 'network'),\n        'region': raw_attrs['region'],\n        'security_groups': parse_list(raw_attrs, 'security_groups'),\n        #ansible\n        'ansible_ssh_port': 22,\n        'ansible_ssh_user': 'centos',\n    }\n\n    try:\n        attrs.update({\n            'ansible_ssh_host': raw_attrs['access_ip_v4'],\n            'publicly_routable': True,\n        })\n    except (KeyError, ValueError):\n        attrs.update({'ansible_ssh_host': '', 'publicly_routable': False, })\n\n    # attrs specific to microservices-infrastructure\n    attrs.update({\n        'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['region'])),\n        'role': attrs['metadata'].get('role', 'none')\n    })\n\n    # add groups based on attrs\n    groups.append('os_image=' + attrs['image']['name'])\n    groups.append('os_flavor=' + attrs['flavor']['name'])\n    groups.extend('os_metadata_%s=%s' % item\n                  for item in attrs['metadata'].items())\n    groups.append('os_region=' + attrs['region'])\n\n    # groups specific to microservices-infrastructure\n    groups.append('role=' + attrs['metadata'].get('role', 'none'))\n    groups.append('dc=' + attrs['consul_dc'])\n\n    return name, attrs, groups\n\n\n@parses('google_compute_instance')\n@calculate_mi_vars\ndef gce_host(resource, tfvars=None):\n    name = resource['primary']['id']\n    raw_attrs = resource['primary']['attributes']\n    groups = []\n\n    # network interfaces\n    interfaces = parse_attr_list(raw_attrs, 'network_interface')\n    for interface in interfaces:\n        interface['access_config'] = parse_attr_list(interface,\n                                                     'access_config')\n        for key in interface.keys():\n            if '.' in key:\n                del interface[key]\n\n    # general attrs\n    attrs = {\n        'can_ip_forward': raw_attrs['can_ip_forward'] == 'true',\n        'disks': parse_attr_list(raw_attrs, 'disk'),\n        'machine_type': raw_attrs['machine_type'],\n        'metadata': parse_dict(raw_attrs, 'metadata'),\n        'network': parse_attr_list(raw_attrs, 'network'),\n        'network_interface': interfaces,\n        'self_link': raw_attrs['self_link'],\n        'service_account': parse_attr_list(raw_attrs, 'service_account'),\n        'tags': parse_list(raw_attrs, 'tags'),\n        'zone': raw_attrs['zone'],\n        # ansible\n        'ansible_ssh_port': 22,\n        'ansible_ssh_user': 'deploy',\n    }\n\n    # attrs specific to microservices-infrastructure\n    attrs.update({\n        'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['zone'])),\n        'role': attrs['metadata'].get('role', 'none')\n    })\n\n    try:\n        attrs.update({\n            'ansible_ssh_host': interfaces[0]['access_config'][0]['nat_ip'],\n            'publicly_routable': True,\n        })\n    except (KeyError, ValueError):\n        attrs.update({'ansible_ssh_host': '', 'publicly_routable': False})\n\n    # add groups based on attrs\n    groups.extend('gce_image=' + disk['image'] for disk in attrs['disks'])\n    groups.append('gce_machine_type=' + attrs['machine_type'])\n    groups.extend('gce_metadata_%s=%s' % (key, value)\n                  for (key, value) in attrs['metadata'].items()\n                  if key not in set(['sshKeys']))\n    groups.extend('gce_tag=' + tag for tag in attrs['tags'])\n    groups.append('gce_zone=' + attrs['zone'])\n\n    if attrs['can_ip_forward']:\n        groups.append('gce_ip_forward')\n    if attrs['publicly_routable']:\n        groups.append('gce_publicly_routable')\n\n    # groups specific to microservices-infrastructure\n    groups.append('role=' + attrs['metadata'].get('role', 'none'))\n    groups.append('dc=' + attrs['consul_dc'])\n\n    return name, attrs, groups\n\n\n## QUERY TYPES\ndef query_host(hosts, target):\n    for name, attrs, _ in hosts:\n        if name == target:\n            return attrs\n\n    return {}\n\n\ndef query_list(hosts):\n    groups = defaultdict(dict)\n    meta = {}\n\n    for name, attrs, hostgroups in hosts:\n        for group in set(hostgroups):\n            groups[group].setdefault('hosts', [])\n            groups[group]['hosts'].append(name)\n\n        meta[name] = attrs\n\n    groups['_meta'] = {'hostvars': meta}\n    return groups\n\n\ndef main():\n\n    parser = argparse.ArgumentParser(__file__, __doc__)\n    modes = parser.add_mutually_exclusive_group(required=True)\n    modes.add_argument('--list',\n                       action='store_true',\n                       help='list all variables')\n    modes.add_argument('--host', help='list variables for a single host')\n    parser.add_argument('--pretty',\n                        action='store_true',\n                        help='pretty-print output JSON')\n    parser.add_argument('--nometa',\n                        action='store_true',\n                        help='with --list, exclude hostvars')\n\n    args = parser.parse_args()\n\n    hosts = iterhosts(iterresources(tfstates()))\n    if args.list:\n        output = query_list(hosts)\n        if args.nometa:\n            del output['_meta']\n    else:\n        output = query_host(hosts, args.host)\n\n    print(json.dumps(output, indent=4 if args.pretty else None))\n    parser.exit()\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/inventory/terraform.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\"\"\"\\\nDynamic inventory for Terraform - finds all `.tfstate` files below the working\ndirectory and generates an inventory based on them.\n\"\"\"\nfrom __future__ import unicode_literals, print_function\nimport argparse\nfrom collections import defaultdict\nfrom functools import wraps\nimport json\nimport os\nimport re\n\n\ndef tfstates(root=None):\n    root = root or os.getcwd()\n    for dirpath, _, filenames in os.walk(root):\n        for name in filenames:\n            if os.path.splitext(name)[-1] == '.tfstate':\n                yield os.path.join(dirpath, name)\n\n\ndef iterresources(filenames):\n    for filename in filenames:\n        with open(filename, 'r') as json_file:\n            state = json.load(json_file)\n            for module in state['modules']:\n                for key, resource in module['resources'].items():\n                    yield key, resource\n\n## READ RESOURCES\nPARSERS = {}\n\n\ndef _clean_dc(dcname):\n    # Consul DCs are strictly alphanumeric with underscores and hyphens -\n    # ensure that the consul_dc attribute meets these requirements.\n    return re.sub('[^\\w_\\-]', '-', dcname)\n\n\ndef iterhosts(resources):\n    '''yield host tuples of (name, attributes, groups)'''\n    for key, resource in resources:\n        resource_type, name = key.split('.', 1)\n        try:\n            parser = PARSERS[resource_type]\n        except KeyError:\n            continue\n\n        yield parser(resource)\n\n\ndef parses(prefix):\n    def inner(func):\n        PARSERS[prefix] = func\n        return func\n\n    return inner\n\n\ndef calculate_mi_vars(func):\n    \"\"\"calculate microservices-infrastructure vars\"\"\"\n\n    @wraps(func)\n    def inner(*args, **kwargs):\n        name, attrs, groups = func(*args, **kwargs)\n\n        # attrs\n        if attrs['role'] == 'control':\n            attrs['consul_is_server'] = True\n        elif attrs['role'] == 'worker':\n            attrs['consul_is_server'] = False\n\n        # groups\n        if attrs.get('publicly_routable', False):\n            groups.append('publicly_routable')\n\n        return name, attrs, groups\n\n    return inner\n\n\ndef _parse_prefix(source, prefix, sep='.'):\n    for compkey, value in source.items():\n        try:\n            curprefix, rest = compkey.split(sep, 1)\n        except ValueError:\n            continue\n\n        if curprefix != prefix or rest == '#':\n            continue\n\n        yield rest, value\n\n\ndef parse_attr_list(source, prefix, sep='.'):\n    size_key = '%s%s#' % (prefix, sep)\n    try:\n        size = int(source[size_key])\n    except KeyError:\n        return []\n\n    attrs = [{} for _ in range(size)]\n    for compkey, value in _parse_prefix(source, prefix, sep):\n        nth, key = compkey.split(sep, 1)\n        attrs[int(nth)][key] = value\n\n    return attrs\n\n\ndef parse_dict(source, prefix, sep='.'):\n    return dict(_parse_prefix(source, prefix, sep))\n\n\ndef parse_list(source, prefix, sep='.'):\n    return [value for _, value in _parse_prefix(source, prefix, sep)]\n\n\ndef parse_bool(string_form):\n    token = string_form.lower()[0]\n\n    if token == 't':\n        return True\n    elif token == 'f':\n        return False\n    else:\n        raise ValueError('could not convert %r to a bool' % string_form)\n\n\n@parses('openstack_compute_instance_v2')\n@calculate_mi_vars\ndef openstack_host(resource, tfvars=None):\n    raw_attrs = resource['primary']['attributes']\n    name = raw_attrs['name']\n    groups = []\n\n    attrs = {\n        'access_ip_v4': raw_attrs['access_ip_v4'],\n        'access_ip_v6': raw_attrs['access_ip_v6'],\n        'flavor': parse_dict(raw_attrs, 'flavor',\n                             sep='_'),\n        'id': raw_attrs['id'],\n        'image': parse_dict(raw_attrs, 'image',\n                            sep='_'),\n        'key_pair': raw_attrs['key_pair'],\n        'metadata': parse_dict(raw_attrs, 'metadata'),\n        'network': parse_attr_list(raw_attrs, 'network'),\n        'region': raw_attrs['region'],\n        'security_groups': parse_list(raw_attrs, 'security_groups'),\n        #ansible\n        'ansible_ssh_port': 22,\n        'ansible_ssh_user': 'centos',\n    }\n\n    try:\n        attrs.update({\n            'ansible_ssh_host': raw_attrs['access_ip_v4'],\n            'publicly_routable': True,\n        })\n    except (KeyError, ValueError):\n        attrs.update({'ansible_ssh_host': '', 'publicly_routable': False, })\n\n    # attrs specific to microservices-infrastructure\n    attrs.update({\n        'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['region'])),\n        'role': attrs['metadata'].get('role', 'none')\n    })\n\n    # add groups based on attrs\n    groups.append('os_image=' + attrs['image']['name'])\n    groups.append('os_flavor=' + attrs['flavor']['name'])\n    groups.extend('os_metadata_%s=%s' % item\n                  for item in attrs['metadata'].items())\n    groups.append('os_region=' + attrs['region'])\n\n    # groups specific to microservices-infrastructure\n    groups.append('role=' + attrs['metadata'].get('role', 'none'))\n    groups.append('dc=' + attrs['consul_dc'])\n\n    return name, attrs, groups\n\n\n@parses('aws_instance')\n@calculate_mi_vars\ndef aws_host(resource, tfvars=None):\n    name = resource['primary']['attributes']['tags.Name']\n    raw_attrs = resource['primary']['attributes']\n\n    groups = []\n\n    attrs = {\n        'ami': raw_attrs['ami'],\n        'availability_zone': raw_attrs['availability_zone'],\n        'ebs_block_device': parse_attr_list(raw_attrs, 'ebs_block_device'),\n        'ebs_optimized': parse_bool(raw_attrs['ebs_optimized']),\n        'ephemeral_block_device': parse_attr_list(raw_attrs,\n                                                  'ephemeral_block_device'),\n        'id': raw_attrs['id'],\n        'key_name': raw_attrs['key_name'],\n        'private': parse_dict(raw_attrs, 'private',\n                              sep='_'),\n        'public': parse_dict(raw_attrs, 'public',\n                             sep='_'),\n        'root_block_device': parse_attr_list(raw_attrs, 'root_block_device'),\n        'security_groups': parse_attr_list(raw_attrs, 'security_groups'),\n        'subnet': parse_dict(raw_attrs, 'subnet',\n                             sep='_'),\n        'tags': parse_dict(raw_attrs, 'tags'),\n        'tenancy': raw_attrs['tenancy'],\n        'vpc_security_group_ids': parse_list(raw_attrs,\n                                             'vpc_security_group_ids'),\n        # ansible-specific\n        'ansible_ssh_port': 22,\n        'ansible_ssh_user': raw_attrs['tags.sshUser'],\n        'ansible_ssh_host': raw_attrs['public_ip'],\n    }\n\n    # attrs specific to microservices-infrastructure\n    attrs.update({\n        'consul_dc': attrs['tags'].get('dc'),\n        'role': attrs['tags'].get('role', 'none')\n    })\n\n    # groups specific to microservices-infrastructure\n    groups.extend(['aws_ami=' + attrs['ami'],\n                   'aws_az=' + attrs['availability_zone'],\n                   'aws_key_name=' + attrs['key_name'],\n                   'aws_tenancy=' + attrs['tenancy']])\n    groups.extend('aws_tag_%s=%s' % item for item in attrs['tags'].items())\n    groups.extend('aws_vpc_security_group=' + group\n                  for group in attrs['vpc_security_group_ids'])\n    groups.extend('aws_subnet_%s=%s' % subnet\n                  for subnet in attrs['subnet'].items())\n\n    # groups specific to microservices-infrastructure\n    groups.append('role=' + attrs['role'])\n    groups.append('dc=' + attrs['consul_dc'])\n\n    return name, attrs, groups\n\n\n@parses('google_compute_instance')\n@calculate_mi_vars\ndef gce_host(resource, tfvars=None):\n    name = resource['primary']['id']\n    raw_attrs = resource['primary']['attributes']\n    groups = []\n\n    # network interfaces\n    interfaces = parse_attr_list(raw_attrs, 'network_interface')\n    for interface in interfaces:\n        interface['access_config'] = parse_attr_list(interface,\n                                                     'access_config')\n        for key in interface.keys():\n            if '.' in key:\n                del interface[key]\n\n    # general attrs\n    attrs = {\n        'can_ip_forward': raw_attrs['can_ip_forward'] == 'true',\n        'disks': parse_attr_list(raw_attrs, 'disk'),\n        'machine_type': raw_attrs['machine_type'],\n        'metadata': parse_dict(raw_attrs, 'metadata'),\n        'network': parse_attr_list(raw_attrs, 'network'),\n        'network_interface': interfaces,\n        'self_link': raw_attrs['self_link'],\n        'service_account': parse_attr_list(raw_attrs, 'service_account'),\n        'tags': parse_list(raw_attrs, 'tags'),\n        'zone': raw_attrs['zone'],\n        # ansible\n        'ansible_ssh_port': 22,\n        'ansible_ssh_user': 'deploy',\n    }\n\n    # attrs specific to microservices-infrastructure\n    attrs.update({\n        'consul_dc': _clean_dc(attrs['metadata'].get('dc', attrs['zone'])),\n        'role': attrs['metadata'].get('role', 'none')\n    })\n\n    try:\n        attrs.update({\n            'ansible_ssh_host': interfaces[0]['access_config'][0]['nat_ip'],\n            'publicly_routable': True,\n        })\n    except (KeyError, ValueError):\n        attrs.update({'ansible_ssh_host': '', 'publicly_routable': False})\n\n    # add groups based on attrs\n    groups.extend('gce_image=' + disk['image'] for disk in attrs['disks'])\n    groups.append('gce_machine_type=' + attrs['machine_type'])\n    groups.extend('gce_metadata_%s=%s' % (key, value)\n                  for (key, value) in attrs['metadata'].items()\n                  if key not in set(['sshKeys']))\n    groups.extend('gce_tag=' + tag for tag in attrs['tags'])\n    groups.append('gce_zone=' + attrs['zone'])\n\n    if attrs['can_ip_forward']:\n        groups.append('gce_ip_forward')\n    if attrs['publicly_routable']:\n        groups.append('gce_publicly_routable')\n\n    # groups specific to microservices-infrastructure\n    groups.append('role=' + attrs['metadata'].get('role', 'none'))\n    groups.append('dc=' + attrs['consul_dc'])\n\n    return name, attrs, groups\n\n\n## QUERY TYPES\ndef query_host(hosts, target):\n    for name, attrs, _ in hosts:\n        if name == target:\n            return attrs\n\n    return {}\n\n\ndef query_list(hosts):\n    groups = defaultdict(dict)\n    meta = {}\n\n    for name, attrs, hostgroups in hosts:\n        for group in set(hostgroups):\n            groups[group].setdefault('hosts', [])\n            groups[group]['hosts'].append(name)\n\n        meta[name] = attrs\n\n    groups['_meta'] = {'hostvars': meta}\n    return groups\n\n\ndef main():\n\n    parser = argparse.ArgumentParser(__file__, __doc__)\n    modes = parser.add_mutually_exclusive_group(required=True)\n    modes.add_argument('--list',\n                       action='store_true',\n                       help='list all variables')\n    modes.add_argument('--host', help='list variables for a single host')\n    parser.add_argument('--pretty',\n                        action='store_true',\n                        help='pretty-print output JSON')\n    parser.add_argument('--nometa',\n                        action='store_true',\n                        help='with --list, exclude hostvars')\n\n    args = parser.parse_args()\n\n    hosts = iterhosts(iterresources(tfstates()))\n    if args.list:\n        output = query_list(hosts)\n        if args.nometa:\n            del output['_meta']\n    else:\n        output = query_host(hosts, args.host)\n\n    print(json.dumps(output, indent=4 if args.pretty else None))\n    parser.exit()\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/inventory/terraform.py"}]}