From faf8fc62cb74f442c2446ac6f5798cecd107feff Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Thu, 17 Oct 2019 21:18:07 +0200 Subject: [PATCH] Add inventory cache to the netbox plugin (#57644) * Add cache to netbox inventory plugin * add changelog fragment --- changelogs/fragments/netbox-add-cache.yaml | 2 + lib/ansible/plugins/inventory/netbox.py | 57 +++++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 changelogs/fragments/netbox-add-cache.yaml diff --git a/changelogs/fragments/netbox-add-cache.yaml b/changelogs/fragments/netbox-add-cache.yaml new file mode 100644 index 00000000000000..d7958f405b4b38 --- /dev/null +++ b/changelogs/fragments/netbox-add-cache.yaml @@ -0,0 +1,2 @@ +minor_changes: + - netbox - use inventory cache if configured diff --git a/lib/ansible/plugins/inventory/netbox.py b/lib/ansible/plugins/inventory/netbox.py index 9120b9d5eb38a7..a527e06e5a3ee7 100644 --- a/lib/ansible/plugins/inventory/netbox.py +++ b/lib/ansible/plugins/inventory/netbox.py @@ -12,11 +12,13 @@ - Remy Leone (@sieben) - Anthony Ruhier (@Anthony25) - Nikhil Singh Baliyan (@nikkytub) + - Sander Steffann (@steffann) short_description: NetBox inventory source description: - Get inventory hosts from NetBox extends_documentation_fragment: - constructed + - inventory_cache options: plugin: description: token that ensures this is a source file for the 'netbox' plugin. @@ -118,12 +120,12 @@ from threading import Thread from itertools import chain -from ansible.plugins.inventory import BaseInventoryPlugin, Constructable +from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.errors import AnsibleError from ansible.module_utils._text import to_text from ansible.module_utils.urls import open_url -from ansible.module_utils.six.moves.urllib.parse import urljoin, urlencode +from ansible.module_utils.six.moves.urllib.parse import urlencode from ansible.module_utils.compat.ipaddress import ip_interface ALLOWED_DEVICE_QUERY_PARAMETERS = ( @@ -158,21 +160,51 @@ ) -class InventoryModule(BaseInventoryPlugin, Constructable): +class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): NAME = 'netbox' def _fetch_information(self, url): - response = open_url(url, headers=self.headers, timeout=self.timeout, validate_certs=self.validate_certs) + results = None + cache_key = self.get_cache_key(url) + + # get the user's cache option to see if we should save the cache if it is changing + user_cache_setting = self.get_option('cache') + + # read if the user has caching enabled and the cache isn't being refreshed + attempt_to_read_cache = user_cache_setting and self.use_cache + + # attempt to read the cache if inventory isn't being refreshed and the user has caching enabled + if attempt_to_read_cache: + try: + results = self._cache[cache_key] + need_to_fetch = False + except KeyError: + # occurs if the cache_key is not in the cache or if the cache_key expired + # we need to fetch the URL now + need_to_fetch = True + else: + # not reading from cache so do fetch + need_to_fetch = True - try: - raw_data = to_text(response.read(), errors='surrogate_or_strict') - except UnicodeError: - raise AnsibleError("Incorrect encoding of fetched payload from NetBox API.") + if need_to_fetch: + self.display.v("Fetching: " + url) + response = open_url(url, headers=self.headers, timeout=self.timeout, validate_certs=self.validate_certs) - try: - return json.loads(raw_data) - except ValueError: - raise AnsibleError("Incorrect JSON payload: %s" % raw_data) + try: + raw_data = to_text(response.read(), errors='surrogate_or_strict') + except UnicodeError: + raise AnsibleError("Incorrect encoding of fetched payload from NetBox API.") + + try: + results = json.loads(raw_data) + except ValueError: + raise AnsibleError("Incorrect JSON payload: %s" % raw_data) + + # put result in cache if enabled + if user_cache_setting: + self._cache[cache_key] = results + + return results def get_resource_list(self, api_url): """Retrieves resource list from netbox API. @@ -446,6 +478,7 @@ def main(self): def parse(self, inventory, loader, path, cache=True): super(InventoryModule, self).parse(inventory, loader, path) self._read_config_data(path=path) + self.use_cache = cache # Netbox access token = self.get_option("token")