Improve speed of the gpc_compute dynamic inventory (#57591)

To get all instances gcp_compute made a call to the Google API for each
zone separately. Because of this if all zones needed to be queried
fetching hosts lasted 30+ seconds. Now the module will use a single
query that will return all the instances, so the execution should last
just a few seconds.

This commit also suppresses a warning from the google-auth library about
using user credentials because if an Ansible user wants to use user
credentials, there is no need to warn him about it.
This commit is contained in:
Strahinja Kustudic 2019-06-12 22:38:48 +02:00 committed by Alex Stephen
parent 0752ca5bed
commit 23e26bf6cd

View file

@ -33,7 +33,7 @@ DOCUMENTATION = '''
filters: filters:
description: > description: >
A list of filter value pairs. Available filters are listed here A list of filter value pairs. Available filters are listed here
U(https://cloud.google.com/compute/docs/reference/rest/v1/instances/list). U(https://cloud.google.com/compute/docs/reference/rest/v1/instances/aggregatedList).
Each additional filter in the list will act be added as an AND condition Each additional filter in the list will act be added as an AND condition
(filter1 and filter2) (filter1 and filter2)
type: list type: list
@ -139,7 +139,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
NAME = 'gcp_compute' NAME = 'gcp_compute'
_instances = r"https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instances" _instances = r"https://www.googleapis.com/compute/v1/projects/%s/aggregated/instances"
def __init__(self): def __init__(self):
super(InventoryModule, self).__init__() super(InventoryModule, self).__init__()
@ -181,18 +181,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
response = self.auth_session.get(link, params={'filter': query}) response = self.auth_session.get(link, params={'filter': query})
return self._return_if_object(self.fake_module, response) return self._return_if_object(self.fake_module, response)
def _get_zones(self, project, config_data):
'''
:param config_data: dict of info from inventory file
:return an array of zones that this project has access to
'''
link = "https://www.googleapis.com/compute/v1/projects/%s/zones" % project
zones = []
zones_response = self.fetch_list(config_data, link, '')
for item in zones_response['items']:
zones.append(item['name'])
return zones
def _get_query_options(self, filters): def _get_query_options(self, filters):
''' '''
:param config_data: contents of the inventory config file :param config_data: contents of the inventory config file
@ -238,7 +226,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
if navigate_hash(result, ['error', 'errors']): if navigate_hash(result, ['error', 'errors']):
module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
if result['kind'] != 'compute#instanceList' and result['kind'] != 'compute#zoneList': if result['kind'] != 'compute#instanceAggregatedList' and result['kind'] != 'compute#zoneList':
module.fail_json(msg="Incorrect result: {kind}".format(**result)) module.fail_json(msg="Incorrect result: {kind}".format(**result))
return result return result
@ -471,16 +459,17 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
for project in params['projects']: for project in params['projects']:
cached_data[project] = {} cached_data[project] = {}
params['project'] = project params['project'] = project
if not params['zones']: zones = params['zones']
zones = self._get_zones(project, params) # Fetch all instances
else: link = self._instances % project
zones = params['zones'] resp = self.fetch_list(params, link, query)
for zone in zones: for key, value in resp.get('items').items():
link = self._instances % (project, zone) if 'instances' in value:
params['zone'] = zone # Key is in format: "zones/europe-west1-b"
resp = self.fetch_list(params, link, query) zone = key[6:]
self._add_hosts(resp.get('items'), config_data, project_disks=project_disks) if not zones or zone in zones:
cached_data[project][zone] = resp.get('items') self._add_hosts(value['instances'], config_data, project_disks=project_disks)
cached_data[project][zone] = value['instances']
if cache_needs_update: if cache_needs_update:
self._cache[cache_key] = cached_data self._cache[cache_key] = cached_data