vim-account and sdn support.
[osm/RO.git] / lcm / osm_common / dbmongo.py
index 38454b3..6bc35a5 100644 (file)
@@ -1,20 +1,54 @@
 #import pymongo
-from pymongo import MongoClient
-from dbbase import DbException, dbbase
+import logging
+from pymongo import MongoClient, errors
+from dbbase import DbException, DbBase
 from http import HTTPStatus
+from time import time, sleep
 
-class dbmongo(dbbase):
+__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
 
-    def __init__(self):
-        pass
+# TODO consider use this decorator for database access retries
+# @retry_mongocall
+# def retry_mongocall(call):
+#     def _retry_mongocall(*args, **kwargs):
+#         retry = 1
+#         while True:
+#             try:
+#                 return call(*args, **kwargs)
+#             except pymongo.AutoReconnect as e:
+#                 if retry == 4:
+#                     raise DbException(str(e))
+#                 sleep(retry)
+#     return _retry_mongocall
+
+
+class DbMongo(DbBase):
+    conn_initial_timout = 120
+    conn_timout = 10
+
+    def __init__(self, logger_name='db'):
+        self.logger = logging.getLogger(logger_name)
 
     def db_connect(self, config):
         try:
+            if "logger_name" in config:
+                self.logger = logging.getLogger(config["logger_name"])
             self.client = MongoClient(config["host"], config["port"])
             self.db = self.client[config["name"]]
+            if "loglevel" in config:
+                self.logger.setLevel(getattr(logging, config['loglevel']))
             # get data to try a connection
-            self.db.users.find_one({"username": "admin"})
-        except Exception as e:  # TODO refine
+            now = time()
+            while True:
+                try:
+                    self.db.users.find_one({"username": "admin"})
+                    return
+                except errors.ConnectionFailure as e:
+                    if time() - now >= self.conn_initial_timout:
+                        raise
+                    self.logger.info("Waiting to database up {}".format(e))
+                    sleep(2)
+        except errors.PyMongoError as e:
             raise DbException(str(e))
 
     def db_disconnect(self):
@@ -30,7 +64,7 @@ class dbmongo(dbbase):
                                                                "ncont", "neq"):
                     operator = "$" + query_k[dot_index+1:]
                     if operator == "$neq":
-                        operator = "$nq"
+                        operator = "$ne"
                     k = query_k[:dot_index]
                 else:
                     operator = "$eq"
@@ -62,8 +96,7 @@ class dbmongo(dbbase):
             return db_filter
         except Exception as e:
             raise DbException("Invalid query string filter at {}:{}. Error: {}".format(query_k, v, e),
-                              http_code=HTTPStatus.BAD_REQUEST.value)
-
+                              http_code=HTTPStatus.BAD_REQUEST)
 
     def get_list(self, table, filter={}):
         try:
@@ -88,12 +121,13 @@ class dbmongo(dbbase):
             rows = collection.find(filter)
             if rows.count() == 0:
                 if fail_on_empty:
-                    raise DbException("Not found entry with filter='{}'".format(filter), HTTPStatus.NOT_FOUND.value)
+                    raise DbException("Not found any {} with filter='{}'".format(table[:-1], filter),
+                                      HTTPStatus.NOT_FOUND)
                 return None
             elif rows.count() > 1:
                 if fail_on_more:
-                    raise DbException("Found more than one entry with filter='{}'".format(filter),
-                                      HTTPStatus.CONFLICT.value)
+                    raise DbException("Found more than one {} with filter='{}'".format(table[:-1], filter),
+                                      HTTPStatus.CONFLICT)
             return rows[0]
         except Exception as e:  # TODO refine
             raise DbException(str(e))
@@ -114,7 +148,8 @@ class dbmongo(dbbase):
             rows = collection.delete_one(self._format_filter(filter))
             if rows.deleted_count == 0:
                 if fail_on_empty:
-                    raise DbException("Not found entry with filter='{}'".format(filter), HTTPStatus.NOT_FOUND.value)
+                    raise DbException("Not found any {} with filter='{}'".format(table[:-1], filter),
+                                      HTTPStatus.NOT_FOUND)
                 return None
             return {"deleted": rows.deleted_count}
         except Exception as e:  # TODO refine
@@ -134,7 +169,8 @@ class dbmongo(dbbase):
             rows = collection.update_one(self._format_filter(filter), {"$set": update_dict})
             if rows.updated_count == 0:
                 if fail_on_empty:
-                    raise DbException("Not found entry with filter='{}'".format(filter), HTTPStatus.NOT_FOUND.value)
+                    raise DbException("Not found any {} with filter='{}'".format(table[:-1], filter),
+                                      HTTPStatus.NOT_FOUND)
                 return None
             return {"deleted": rows.deleted_count}
         except Exception as e:  # TODO refine
@@ -142,11 +178,13 @@ class dbmongo(dbbase):
 
     def replace(self, table, id, indata, fail_on_empty=True):
         try:
+            _filter = {"_id": id}
             collection = self.db[table]
-            rows = collection.replace_one({"_id": id}, indata)
-            if rows.modified_count == 0:
+            rows = collection.replace_one(_filter, indata)
+            if rows.matched_count == 0:
                 if fail_on_empty:
-                    raise DbException("Not found entry with filter='{}'".format(filter), HTTPStatus.NOT_FOUND.value)
+                    raise DbException("Not found any {} with filter='{}'".format(table[:-1], _filter),
+                                      HTTPStatus.NOT_FOUND)
                 return None
             return {"replace": rows.modified_count}
         except Exception as e:  # TODO refine