From 901923e6480dd2a26327e48bd6b03d50bb36f74b Mon Sep 17 00:00:00 2001
From: Erik Reid <erik.reid@geant.org>
Date: Mon, 25 May 2020 21:05:04 +0200
Subject: [PATCH] use current data, in case of snmp/netconf errors

---
 inventory_provider/tasks/worker.py | 56 ++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py
index 6c965ae9..6af7b324 100644
--- a/inventory_provider/tasks/worker.py
+++ b/inventory_provider/tasks/worker.py
@@ -12,7 +12,8 @@ import jsonschema
 
 from inventory_provider.tasks.app import app
 from inventory_provider.tasks.common \
-    import get_next_redis, latch_db, get_latch, set_latch, update_latch_status
+    import get_next_redis, get_current_redis, \
+    latch_db, get_latch, set_latch, update_latch_status
 from inventory_provider.tasks import data
 from inventory_provider import config
 from inventory_provider import environment
@@ -108,22 +109,57 @@ class InventoryTask(Task):
 @app.task(base=InventoryTask, bind=True, name='snmp_refresh_interfaces')
 @log_task_entry_and_exit
 def snmp_refresh_interfaces(self, hostname, community):
-    # TODO: [DBOARD3-242] copy from current redis in case of error
-    value = list(snmp.get_router_snmp_indexes(hostname, community))
+    warning = False
+    try:
+        value = list(snmp.get_router_snmp_indexes(hostname, community))
+    except ConnectionError:
+        logger.exception(f'error loading snmp data from {hostname}')
+        warning = True
+        r = get_current_redis(InventoryTask.config)
+        value = r.get(f'snmp-interfaces:{hostname}')
+        if not value:
+            raise InventoryTaskError(
+                f'snmp error with {hostname}'
+                f' and no cached netconf data found')
+        # unnecessary json encode/decode here ... could be optimized
+        value = json.loads(value.decode('utf-8'))
+
     r = get_next_redis(InventoryTask.config)
-    r.set('snmp-interfaces:' + hostname, json.dumps(value))
-    return self.success(message=f'snmp info loaded from {hostname}')
+    r.set(f'snmp-interfaces:{hostname}', json.dumps(value))
+
+    if warning:
+        return self.warning(
+            message=f'i/o error with {hostname}, using cached snmp info')
+    else:
+        return self.success(message=f'snmp info loaded from {hostname}')
 
 
 @app.task(base=InventoryTask, bind=True, name='netconf_refresh_config')
 @log_task_entry_and_exit
 def netconf_refresh_config(self, hostname):
-    # TODO: [DBOARD3-242] copy from current redis in case of error
-    netconf_doc = juniper.load_config(hostname, InventoryTask.config["ssh"])
-    netconf_str = etree.tostring(netconf_doc, encoding='unicode')
+
+    warning = False
+    try:
+        netconf_doc = juniper.load_config(hostname, InventoryTask.config["ssh"])
+        netconf_str = etree.tostring(netconf_doc, encoding='unicode')
+    except ConnectionError:
+        logger.exception(f'error loading netconf data from {hostname}')
+        warning = True
+        r = get_current_redis(InventoryTask.config)
+        netconf_str = r.get(f'netconf:{hostname}')
+        if not netconf_str:
+            raise InventoryTaskError(
+                f'netconf error with {hostname}'
+                f' and no cached netconf data found')
+
     r = get_next_redis(InventoryTask.config)
-    r.set('netconf:' + hostname, netconf_str)
-    return self.success(message=f'netconf info loaded from {hostname}')
+    r.set(f'netconf:{hostname}', netconf_str)
+
+    if warning:
+        return self.warning(
+            message=f'i/o error with {hostname}, using cached netconf info')
+    else:
+        return self.success(message=f'netconf info loaded from {hostname}')
 
 
 @app.task(base=InventoryTask, bind=True, name='update_interfaces_to_services')
-- 
GitLab