From 840bdc1e10f1f0d3c8c0ce4109e9724b466202c0 Mon Sep 17 00:00:00 2001 From: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> Date: Mon, 1 Feb 2021 14:29:36 -0500 Subject: [PATCH] Fix warning for nonexistent inventory cache (#72840) * Fix inventory cache warning by checking if the key exists before loading it * changelog --- .../inventory-cache-file-missing-warning.yaml | 2 + lib/ansible/plugins/cache/__init__.py | 13 +++-- .../targets/inventory_cache/aliases | 1 + .../targets/inventory_cache/cache/.keep | 0 .../targets/inventory_cache/cache_host.yml | 4 ++ .../plugins/inventory/cache_host.py | 56 +++++++++++++++++++ .../targets/inventory_cache/runme.sh | 23 ++++++++ 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/inventory-cache-file-missing-warning.yaml create mode 100644 test/integration/targets/inventory_cache/aliases create mode 100644 test/integration/targets/inventory_cache/cache/.keep create mode 100644 test/integration/targets/inventory_cache/cache_host.yml create mode 100644 test/integration/targets/inventory_cache/plugins/inventory/cache_host.py create mode 100755 test/integration/targets/inventory_cache/runme.sh diff --git a/changelogs/fragments/inventory-cache-file-missing-warning.yaml b/changelogs/fragments/inventory-cache-file-missing-warning.yaml new file mode 100644 index 00000000000..3ef58c3e072 --- /dev/null +++ b/changelogs/fragments/inventory-cache-file-missing-warning.yaml @@ -0,0 +1,2 @@ +minor_changes: + - inventory cache - do not show a warning when the cache file does not (yet) exist. diff --git a/lib/ansible/plugins/cache/__init__.py b/lib/ansible/plugins/cache/__init__.py index 3c4613c983d..3613acaddde 100644 --- a/lib/ansible/plugins/cache/__init__.py +++ b/lib/ansible/plugins/cache/__init__.py @@ -319,12 +319,13 @@ class CachePluginAdjudicator(MutableMapping): def _do_load_key(self, key): load = False - if key not in self._cache and key not in self._retrieved and self._plugin_name != 'memory': - if isinstance(self._plugin, BaseFileCacheModule): - load = True - elif not isinstance(self._plugin, BaseFileCacheModule) and self._plugin.contains(key): - # Database-backed caches don't raise KeyError for expired keys, so only load if the key is valid by checking contains() - load = True + if all([ + key not in self._cache, + key not in self._retrieved, + self._plugin_name != 'memory', + self._plugin.contains(key), + ]): + load = True return load def __getitem__(self, key): diff --git a/test/integration/targets/inventory_cache/aliases b/test/integration/targets/inventory_cache/aliases new file mode 100644 index 00000000000..70a7b7a9f32 --- /dev/null +++ b/test/integration/targets/inventory_cache/aliases @@ -0,0 +1 @@ +shippable/posix/group5 diff --git a/test/integration/targets/inventory_cache/cache/.keep b/test/integration/targets/inventory_cache/cache/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/integration/targets/inventory_cache/cache_host.yml b/test/integration/targets/inventory_cache/cache_host.yml new file mode 100644 index 00000000000..3630641b469 --- /dev/null +++ b/test/integration/targets/inventory_cache/cache_host.yml @@ -0,0 +1,4 @@ +plugin: cache_host +cache: true +cache_plugin: jsonfile +cache_connection: ./cache diff --git a/test/integration/targets/inventory_cache/plugins/inventory/cache_host.py b/test/integration/targets/inventory_cache/plugins/inventory/cache_host.py new file mode 100644 index 00000000000..628aba158e0 --- /dev/null +++ b/test/integration/targets/inventory_cache/plugins/inventory/cache_host.py @@ -0,0 +1,56 @@ +# Copyright (c) 2021 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' + inventory: cache_host + short_description: add a host to inventory and cache it + description: add a host to inventory and cache it + extends_documentation_fragment: + - inventory_cache + options: + plugin: + required: true + description: name of the plugin (cache_host) +''' + +from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable +import random + + +class InventoryModule(BaseInventoryPlugin, Cacheable): + + NAME = 'cache_host' + + def verify_file(self, path): + if not path.endswith(('cache_host.yml', 'cache_host.yaml',)): + return False + return super(InventoryModule, self).verify_file(path) + + def parse(self, inventory, loader, path, cache=None): + super(InventoryModule, self).parse(inventory, loader, path) + self._read_config_data(path) + + cache_key = self.get_cache_key(path) + # user has enabled cache and the cache is not being flushed + read_cache = self.get_option('cache') and cache + # user has enabled cache and the cache is being flushed + update_cache = self.get_option('cache') and not cache + + host = None + if read_cache: + try: + host = self._cache[cache_key] + except KeyError: + # cache expired + update_cache = True + + if host is None: + host = 'testhost{0}'.format(random.randint(0, 50)) + + self.inventory.add_host(host, 'all') + + if update_cache: + self._cache[cache_key] = host diff --git a/test/integration/targets/inventory_cache/runme.sh b/test/integration/targets/inventory_cache/runme.sh new file mode 100755 index 00000000000..098439eb227 --- /dev/null +++ b/test/integration/targets/inventory_cache/runme.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -eux + +export ANSIBLE_INVENTORY_PLUGINS=./plugins/inventory + +cleanup() { + for f in ./cache/ansible_inventory*; do + if [ -f "$f" ]; then rm -rf "$f"; fi + done +} + +trap 'cleanup' EXIT + +# Test no warning when writing to the cache for the first time +test "$(ansible-inventory -i cache_host.yml --graph 2>&1 | tee out.txt | grep -c '\[WARNING\]')" = 0 +writehost="$(grep "testhost[0-9]\{1,2\}" out.txt)" + +# Test reading from the cache +test "$(ansible-inventory -i cache_host.yml --graph 2>&1 | tee out.txt | grep -c '\[WARNING\]')" = 0 +readhost="$(grep 'testhost[0-9]\{1,2\}' out.txt)" + +test "$readhost" = "$writehost"