From a22c98c240eba056efeb4e02e5215e7984989018 Mon Sep 17 00:00:00 2001 From: Robert Latta <robert.latta@geant.org> Date: Thu, 19 Aug 2021 15:19:08 +0000 Subject: [PATCH] context corrections --- inventory_provider/routes/common.py | 5 +- inventory_provider/routes/lnetd.py | 3 +- inventory_provider/routes/poller.py | 21 +++-- inventory_provider/routes/testing.py | 6 ++ inventory_provider/tasks/worker.py | 122 ++++++++++++++++++--------- test/test_worker.py | 12 +-- 6 files changed, 112 insertions(+), 57 deletions(-) diff --git a/inventory_provider/routes/common.py b/inventory_provider/routes/common.py index c2eda21e..79d7c481 100644 --- a/inventory_provider/routes/common.py +++ b/inventory_provider/routes/common.py @@ -275,14 +275,13 @@ def load_xml_docs( use_next_redis=use_next_redis) -@functools.lru_cache(maxsize=None) -def load_snmp_indexes(hostname=None, use_next_redis=False): +def load_snmp_indexes(config, hostname=None, use_next_redis=False): result = dict() key_pattern = f'snmp-interfaces:{hostname}*' \ if hostname else 'snmp-interfaces:*' for doc in load_json_docs( - config_params=current_app.config['INVENTORY_PROVIDER_CONFIG'], + config_params=config, key_pattern=key_pattern, use_next_redis=use_next_redis): router = doc['key'][len('snmp-interfaces:'):] diff --git a/inventory_provider/routes/lnetd.py b/inventory_provider/routes/lnetd.py index 346f857e..8402a0e0 100644 --- a/inventory_provider/routes/lnetd.py +++ b/inventory_provider/routes/lnetd.py @@ -74,7 +74,8 @@ def _add_snmp_indexes(interfaces, hostname=None): :param hostname: hostname or None for all :return: generator that yields interfaces with 'ifIndex' added """ - snmp_indexes = common.load_snmp_indexes(hostname) + snmp_indexes = common.load_snmp_indexes( + current_app.config['INVENTORY_PROVIDER_CONFIG'], hostname) for ifc in interfaces: hostname = ifc['hostname'] diff --git a/inventory_provider/routes/poller.py b/inventory_provider/routes/poller.py index c6cf843b..2ec37100 100644 --- a/inventory_provider/routes/poller.py +++ b/inventory_provider/routes/poller.py @@ -584,7 +584,8 @@ def _load_services(config, hostname=None, use_next_redis=False): return result -def _load_interfaces(config, hostname, use_next_redis=False): +def _load_interfaces( + config, hostname=None, no_lab=False, use_next_redis=False): """ loads basic interface data for production & lab routers @@ -623,7 +624,6 @@ def _load_interfaces(config, hostname, use_next_redis=False): base_key_pattern = f'netconf:{hostname}*' if hostname else 'netconf:*' yield from _load_docs(base_key_pattern) - no_lab = common.get_bool_request_arg('no-lab', False) if not no_lab: yield from _load_docs(f'lab:{base_key_pattern}') @@ -679,7 +679,8 @@ def _add_snmp_indexes(interfaces, hostname=None): :param hostname: hostname or None for all :return: generator with 'snmp-index' optionally added to each element """ - snmp_indexes = common.load_snmp_indexes(hostname) + snmp_indexes = common.load_snmp_indexes( + current_app.config['INVENTORY_PROVIDER_CONFIG'], hostname) for ifc in interfaces: router_snmp = snmp_indexes.get(ifc['router'], None) if router_snmp and ifc['name'] in router_snmp: @@ -698,8 +699,12 @@ def _load_interfaces_to_poll(hostname=None): :param hostname: hostname or None for all :return: generator yielding interface elements """ + + no_lab = common.get_bool_request_arg('no-lab', False) basic_interfaces = _load_interfaces( - current_app.config['INVENTORY_PROVIDER_CONFIG'], hostname) + current_app.config['INVENTORY_PROVIDER_CONFIG'], + hostname, + no_lab=no_lab) # basic_interfaces = list(basic_interfaces) with_bundles = _add_bundle_parents(basic_interfaces, hostname) with_circuits = _add_circuits(with_bundles, hostname) @@ -807,8 +812,11 @@ def _load_interfaces_and_speeds(hostname=None): :param hostname: hostname or None for all :return: generator yielding interface elements """ + no_lab = common.get_bool_request_arg('no-lab', False) basic_interfaces = _load_interfaces( - current_app.config['INVENTORY_PROVIDER_CONFIG'], hostname) + current_app.config['INVENTORY_PROVIDER_CONFIG'], + hostname, + no_lab=no_lab) with_bundles = _add_bundle_parents(basic_interfaces, hostname) def _result_ifc(ifc): @@ -1106,7 +1114,8 @@ def _get_services_internal(service_type=None): yield doc['value'] def _add_snmp(s): - all_snmp_info = common.load_snmp_indexes() + all_snmp_info = common.load_snmp_indexes( + current_app.config['INVENTORY_PROVIDER_CONFIG'], ) snmp_interfaces = all_snmp_info.get(s['hostname'], {}) interface_info = snmp_interfaces.get(s['interface'], None) if interface_info: diff --git a/inventory_provider/routes/testing.py b/inventory_provider/routes/testing.py index 8240efe5..ac74703e 100644 --- a/inventory_provider/routes/testing.py +++ b/inventory_provider/routes/testing.py @@ -18,6 +18,12 @@ routes = Blueprint("inventory-data-testing-support-routes", __name__) logger = logging.getLogger(__name__) +@routes.route("just-poller-cache", methods=['GET', 'POST']) +def just_poller_cache_update(): + r = worker.just_poller_cache.delay().get() + return jsonify(r) + + @routes.route("chord-update", methods=['GET', 'POST']) def chord_update(): r = worker.update_entry_point.delay().get() diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py index 1d41d539..743f0fc3 100644 --- a/inventory_provider/tasks/worker.py +++ b/inventory_provider/tasks/worker.py @@ -940,7 +940,7 @@ def refresh_finalizer(self, pending_task_ids_json): _build_subnet_db(update_callback=self.log_info) _build_snmp_peering_db(update_callback=self.log_info) _build_juniper_peering_db(update_callback=self.log_info) - populate_poller_interfaces_cache() + populate_poller_interfaces_cache(warning_callback=self.log_warning) except (jsonschema.ValidationError, json.JSONDecodeError, @@ -1836,55 +1836,93 @@ def final_task(self): self.log_info('latched current/next dbs') -def populate_poller_interfaces_cache(): +def populate_poller_interfaces_cache(warning_callback=lambda s: None): + no_lab_cache_key = 'classifier-cache:poller-interfaces:no-lab' + all_cache_key = 'classifier-cache:poller-interfaces:all' + non_lab_populated_interfaces = None + all_populated_interfaces = None - base_key_pattern = 'netconf:*' - standard_interfaces = _load_interfaces( - InventoryTask.config, base_key_pattern, use_next_redis=True) - lab_interfaces = _load_interfaces( - InventoryTask.config, f'lab:{base_key_pattern}') + r = get_next_redis(InventoryTask.config) - bundles = _load_interface_bundles( - InventoryTask.config, - use_next_redis=True - ) - snmp_indexes = load_snmp_indexes(use_next_redis=True) + try: + lab_keys_pattern = 'lab:netconf-interfaces-hosts:*' + lab_equipment = [h.decode('utf-8')[len(lab_keys_pattern) - 1:] + for h in r.keys(lab_keys_pattern)] + logger.debug(lab_equipment) + standard_interfaces = _load_interfaces( + InventoryTask.config, + no_lab=False, + use_next_redis=True) + + bundles = _load_interface_bundles( + InventoryTask.config, + use_next_redis=True + ) + snmp_indexes = load_snmp_indexes( + InventoryTask.config, use_next_redis=True) - services = _load_services(InventoryTask.config, use_next_redis=True) + services = _load_services(InventoryTask.config, use_next_redis=True) - r = get_next_redis(InventoryTask.config) + def _get_populated_interfaces(interfaces): - def _get_populated_interfaces(interfaces): - for ifc in interfaces: + for ifc in interfaces: + router_snmp = snmp_indexes.get(ifc['router'], None) + if router_snmp and ifc['name'] in router_snmp: + ifc['snmp-index'] = router_snmp[ifc['name']]['index'] - router_snmp = snmp_indexes.get(ifc['router'], None) - if router_snmp and ifc['name'] in router_snmp: - ifc['snmp-index'] = router_snmp[ifc['name']]['index'] + router_bundle = bundles.get(ifc['router'], None) + if router_bundle: + base_ifc = ifc['name'].split('.')[0] + ifc['bundle-parents'] = router_bundle.get(base_ifc, []) - router_bundle = bundles.get(ifc['router'], None) - if router_bundle: - base_ifc = ifc['name'].split('.')[0] - ifc['bundle-parents'] = router_bundle.get(base_ifc, []) + router_services = services.get( + get_ims_equipment_name(ifc['router'], r), None) + if router_services: + ifc['circuits'] = router_services.get( + get_ims_interface(ifc['name']), [] + ) - router_services = services.get( - get_ims_equipment_name(ifc['router'], r), None) - if router_services: - ifc['circuits'] = router_services.get( - get_ims_interface(ifc['name']), [] - ) + dashboards = _get_dashboards(ifc) + ifc['dashboards'] = sorted([d.name for d in dashboards]) + yield _get_dashboard_data(ifc) + else: + continue - dashboards = _get_dashboards(ifc) - ifc['dashboards'] = sorted([d.name for d in dashboards]) - yield _get_dashboard_data(ifc) - else: - continue + all_populated_interfaces = \ + list(_get_populated_interfaces(standard_interfaces)) + non_lab_populated_interfaces = [x for x in all_populated_interfaces + if x['router'] not in lab_equipment] - non_lab_populated_interfaces = \ - list(_get_populated_interfaces(standard_interfaces)) - cache_key = 'classifier-cache:poller-interfaces:no-lab' - r.set(cache_key, json.dumps(non_lab_populated_interfaces)) + except Exception as e: + warning_callback(f"Failed to retrieve all required data {e}") - all_populated_interfaces = non_lab_populated_interfaces + \ - list(_get_populated_interfaces(lab_interfaces)) - cache_key = 'classifier-cache:poller-interfaces:all' - r.set(cache_key, json.dumps(all_populated_interfaces)) + if not non_lab_populated_interfaces or not all_populated_interfaces: + previous_r = get_current_redis(InventoryTask.config) + + def _load_previous(key): + try: + warning_callback(f"populating {key} " + "from previously cached data") + return json.loads(previous_r.get(key)) + except Exception as e: + warning_callback(f"Failed to load {key} " + f"from previously cached data: {e}") + + if not non_lab_populated_interfaces: + non_lab_populated_interfaces = _load_previous(no_lab_cache_key) + + if not all_populated_interfaces: + all_populated_interfaces = _load_previous(all_cache_key) + + r.set(no_lab_cache_key, json.dumps(non_lab_populated_interfaces)) + r.set(all_cache_key, json.dumps(all_populated_interfaces)) + + +@app.task(base=InventoryTask, bind=True, name='just_poller_cache') +@log_task_entry_and_exit +def just_poller_cache(self): + + populate_poller_interfaces_cache(warning_callback=self.log_warning) + + latch_db(InventoryTask.config) + self.log_info('latched current/next dbs') diff --git a/test/test_worker.py b/test/test_worker.py index 34dfd68c..fa254f67 100644 --- a/test/test_worker.py +++ b/test/test_worker.py @@ -330,7 +330,7 @@ def test_retrieve_and_persist_neteng_managed_device_list( def test_populate_poller_interfaces_cache( mocker, data_config, mocked_redis): r = common._get_redis(data_config) - standard_interfaces = [ + all_interfaces = [ { "router": "router_a.geant.net", "name": "interface_a", @@ -355,9 +355,6 @@ def test_populate_poller_interfaces_cache( "description": "DESCRIPTION C", "circuits": [] }, - ] - - lab_interfaces = [ { "router": "lab_router_a.geant.net", "name": "lab_interface_a", @@ -482,8 +479,13 @@ def test_populate_poller_interfaces_cache( }, ] + for k in r.keys("lab:netconf-interfaces-hosts:*"): + r.delete(k) + r.set("lab:netconf-interfaces-hosts:lab_router_a.geant.net", "dummy") + r.set("lab:netconf-interfaces-hosts:lab_router_b.geant.net", "dummy") + mocker.patch('inventory_provider.tasks.worker._load_interfaces', - side_effect=[standard_interfaces, lab_interfaces]) + side_effect=[all_interfaces, ]) mocker.patch('inventory_provider.tasks.worker._load_interface_bundles', return_value=bundles) mocker.patch('inventory_provider.tasks.worker.load_snmp_indexes', -- GitLab