From 096a10cb8f6318f24c1af1ff94fa27f7e68fd339 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20K=C3=A1cha?= <ph@cesnet.cz>
Date: Wed, 14 Jan 2015 18:42:04 +0100
Subject: [PATCH] fetch_events and friends modified to use SQL placeholders

---
 warden3/warden_server/warden_server.py | 174 ++++++++++---------------
 1 file changed, 70 insertions(+), 104 deletions(-)

diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py
index f9b0a04..2d43bb4 100755
--- a/warden3/warden_server/warden_server.py
+++ b/warden3/warden_server/warden_server.py
@@ -307,7 +307,7 @@ class MySQL(Object):
 
         client["services"] = services
 
-        logging.debug("Client/services: " + str(client))
+        logging.debug("get_client_by_name: %s", str(client))
         return client
 
 
@@ -341,73 +341,77 @@ class MySQL(Object):
         }
 
 
+    def generateDynamicQuery(self, section, query_string, variables, parent_cats = []):
+        variables_id = []
+    
+        for v in variables:
+            mapped_id = self.map_id(section, v)
+            if mapped_id % 100:
+                variables_id.append(mapped_id)
+            else:
+                parent_cats.append(mapped_id)
+    
+        format_strings = ','.join(['%s'] * len(variables_id))
+        temp_string = query_string % format_strings
+        
+        return temp_string, variables_id
+
+
     def fetch_events(self, client, id, count,
             cat=None, nocat=None,
             tag=None, notag=None,
             group=None, nogroup=None):
        
-        sqlwhere = []
-        sqltemp = {}
-
         logging.debug("fetch_events: id=%i, count=%i, cat=%s, nocat=%s, tag=%s, notag=%s, group=%s, nogroup=%s" % (id, count, str(cat), str(nocat), str(tag), str(notag), str(group), str(nogroup)))
 
-        if cat is not None and nocat is not None:
+        if cat and nocat:
             raise Error("Unrealizable conditions. Choose cat or nocat option.", 500, method='getEvents', 
                         exc=sys.exc_info(), detail={'cat': cat, 'nocat' : nocat})
-
-        if cat is not None or nocat is not None:
-            if cat is not None:
-                parent_cats = []
-                sqltemp['cat'] = self.generateDynamicQuery("Category", "category_id IN (%s)", cat, parent_cats)
-                for pcats in parent_cats:
-                    sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats)
-            if nocat is not None:
-                parent_cats = []
-                sqltemp['cat'] = self.generateDynamicQuery("Category", "category_id NOT IN (%s)", nocat, parent_cats)
-                for pcats in parent_cats:
-                    sqltemp['cat'] += " %s category_id DIV %s = 1 " % (("OR" if sqltemp['cat'] else ""), pcats)
-                
-            sqlwhere.append("e.id IN (SELECT event_id FROM event_category_mapping WHERE %s)" % sqltemp['cat'])
-
-        if tag is not None and notag is not None:
+        if tag and notag:
             raise Error("Unrealizable conditions. Choose tag or notag option.", 500, method='getEvents', 
                         exc=sys.exc_info(), detail={'tag': cat, 'notag' : nocat})
-
-        if tag is not None or notag is not None:
-            if tag is not None:
-                sqltemp['tag'] = self.generateDynamicQuery("Tag", "tag_id IN (%s)", tag)
-            if notag is not None:
-                sqltemp['tag'] = self.generateDynamicQuery("Tag", "tag_id NOT IN (%s)", notag)
-            
-            sqlwhere.append("e.id IN (SELECT event_id FROM event_tag_mapping WHERE %s)" % sqltemp['tag'])
-
-     
-        if group is not None and nogroup is not None:       
+        if group and nogroup:
             raise Error("Unrealizable conditions. Choose group or nogroup option.", 500, method='getEvents', 
                         exc=sys.exc_info(), detail={'tag': cat, 'notag' : nocat})
 
-        if group is not None or nogroup is not None:
-            sqltemp['group'] = ""
+        sqlwhere = []
+        sqlparams = []
 
-            if group is not None:
-                for identity in group:
-                    sqltemp['group'] += ("s.identity LIKE '%s' AND " % (identity)) 
-            if nogroup is not None:
-                for identity in nogroup:
-                    sqltemp['group'] += ("s.identity NOT LIKE '%s' AND " % (identity)) 
+        sqlwhere.append("SELECT e.id, e.data FROM services s RIGHT JOIN events e ON s.service_id = e.service_id WHERE e.id > %s")
+        sqlparams.append(id or 0)
 
-            # logging.debug(sqltemp['group'][:-4])
-            sqlwhere.append(sqltemp['group'][:-4])
+        if cat or nocat:
+            not_op = "" if cat else "NOT"
+            parent_cats = []
+            sqltemp, sqlpar = self.generateDynamicQuery("Category", "category_id %s IN (%%s)" % not_op, (cat or nocat), parent_cats)
+            for pcats in parent_cats:
+                sqltemp += " %s category_id DIV %s = 1 " % (("OR" if sqltemp else ""), pcats)
+                
+            sqlwhere.append(" AND e.id IN (SELECT event_id FROM event_category_mapping WHERE %s)" % sqltemp)
+            sqlparams.extend(sqlpar)
 
-        sqlwhere_string = (" AND " . join(sqlwhere))
-        # logging.debug(sqlwhere_string)
-        # logging.debug(' AND ' . join(sqlwhere))
-    
-        #sqlwhere = sqlwhere[:-4]
-        and_op = "" if not sqlwhere_string else "AND"
+        if tag or notag:
+            not_op = "" if tag else "NOT"
+            sqltemp, sqlpar = self.generateDynamicQuery("Tag", "tag_id %s IN (%%s)" % not_op, (tag or notag))
+            
+            sqlwhere.append(" AND e.id IN (SELECT event_id FROM event_tag_mapping WHERE %s)" % sqltemp)
+            sqlparams.extend(sqlpar)
+
+        if group or nogroup:
+            not_op = "" if group else "NOT"
+            
+            for identity in (group or nogroup):
+                sqlwhere.append(" AND s.identity %s LIKE %%s" % not_op)
+                sqlparams.append(identity + "%")
 
-        logging.debug("SELECT e.id, e.data FROM services s RIGHT JOIN events e ON s.id = e.service_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id or 0), sqlwhere_string, and_op, str(count)))
-        self.crs.execute("SELECT e.id, e.data FROM services s RIGHT JOIN events e ON s.service_id = e.service_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id or 0), sqlwhere_string, and_op, str(count)))
+        sqlwhere.append(" AND e.valid = 1 LIMIT %s")
+        sqlparams.append(count)
+
+        sqlwhere_string = "".join(sqlwhere)
+        logging.debug("fetch_events: query - %s" % sqlwhere_string)
+        logging.debug("fetch_events: params - %s", str(sqlparams))
+
+        self.crs.execute(sqlwhere_string, sqlparams)
         row = self.crs.fetchall()
 
         if row:
@@ -415,14 +419,11 @@ class MySQL(Object):
         else:
             maxid = self.getLastEventId()
 
-        # logging.debug("MAX ID = %s", str(maxid))
-        #for r in row:
-        #    logging.debug(json.loads(r["data"]))
+        events = [json.loads(r["data"]) for r in row]
 
         return {
             "lastid": maxid,
-            # "lastid": row[-1]['id'] if row else str(id),
-            "events": [json.loads(r["data"]) for r in row]
+            "events": events
         }
 
 
@@ -455,8 +456,8 @@ class MySQL(Object):
 
 
     def insertLastReceivedId(self, client, id):
-        logging.debug("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client["id"]), id))
-        self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())" % (str(client["id"]), id))
+        logging.debug("insertLastReceivedId: id %i for client %i(%s)" % (id, client["id"], client["hostname"]))
+        self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())", (client["id"], id))
 
     def getLastEventId(self):
         self.crs.execute("SELECT MAX(id) as id FROM events")
@@ -465,16 +466,13 @@ class MySQL(Object):
         return row['id'] if row['id'] is not None else 0
 
     def getLastReceivedId(self, client):
-        client_id = client["id"] 
-        logging.debug("getLastReceivedId (client_id) = %s", str(client_id))
-
-        logging.debug("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id)))
-        self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s" % (str(client_id)))
+        self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s", client["id"])
         row = self.crs.fetchone()
 
-        logging.debug("getLastReceivedId - %s" % str(row['id']))
+        id = row['id'] if row is not None else 0
+        logging.debug("getLastReceivedId: id %i for client %i(%s)" % (id, client["id"], client["hostname"]))
 
-        return row['id'] if row is not None else 0
+        return id
 
 
     def map_id (self, section, key):
@@ -556,24 +554,6 @@ class MySQL(Object):
             return data[section][key]
         except KeyError:
             return 0
-
-
-    def generateDynamicQuery(self, section, query_string, variables, parent_cats = []):
-        variables_id = []
-        # parent_cats = []
-    
-        for v in variables:
-            mapped_id = self.map_id(section, v)
-            if mapped_id % 100 != 0:
-                variables_id.append(mapped_id)
-            else:
-                parent_cats.append(mapped_id)
-    
-        # variables_id = [self.map_id(section, v) for v in variables if self.map_id(section, v) % 100 != 0]
-        format_strings = ','.join(['\'%s\''] * len(variables_id))
-        temp_string = query_string % format_strings
-        
-        return temp_string % tuple(variables_id)
     
 
 
@@ -643,21 +623,16 @@ class Server(Object):
                     exc=sys.exc_info(), detail={"args": injson})
 
             args = parse_qs(environ.get('QUERY_STRING', ""))
-            #for k, v in args.iteritems():
-            #    args[k] = v[0]
             logging.debug("%s called with %s" % (path, str(args)))
             if events:
                 args["events"] = events
 
-            # if not self.auth.authorize(environ, client, path, args):
-            #     raise Error("I'm watching YOU.", 403, method=path, detail={"client": client})
-
             args = self.sanitize_args(path, method, args)
             result = method(_env=environ, _client=client, **args)   # call requested method
 
             try:
-            # 'default': takes care of non JSON serializable objects,
-            # which could (although shouldn't) appear in handler code
+                # 'default': takes care of non JSON serializable objects,
+                # which could (although shouldn't) appear in handler code
                 output = json.dumps(result, default=lambda v: str(v))
             except Exception as e:
                 raise Error("Serialization error", 500, method=path,
@@ -748,25 +723,18 @@ class WardenHandler(Object):
         try:
             id = int(id[0])
         except (ValueError, TypeError, IndexError):
-            id = 0
+            id = None
 
-        if not id:
+        if id is None:
             try:
                 id = self.db.getLastReceivedId(_client)
-                # logging.debug("Last received ID for %s is %s" % (_client['hostname'], str(id)))
             except Exception, e:
-                logging.error("getEvents: cannot getLastReceivedId - " + type(e).__name__ + ": " + e)
-                id = 0
+                logging.info("getEvents: cannot getLastReceivedId - " + type(e).__name__ + ": " + e)
                 
-        if not id:
-            try:
-                id = self.db.getLastEventId()
-            except Exception as e:
-                raise Error("Last event id receiving error", 500, detail={"client": _client})
-  
-            # First access, remember the guy
+        if id is None:
+            # First access, remember the guy and get him last event
+            id = self.db.getLastEventId()
             self.db.insertLastReceivedId(_client, id)
-
             return {
                 "lastid": id,
                 "events": []
@@ -780,13 +748,11 @@ class WardenHandler(Object):
         if self.get_events_limit:
             count = min(count, self.get_events_limit)
 
-        logging.debug("getEvents - count: %s" % count)
         res = self.db.fetch_events(_client, id, count, cat, nocat, tag, notag, group, nogroup)
         logging.info("getEvents(%d, %d, %s, %s, %s, %s, %s, %s): sending %d events" % (
             id, count, cat, nocat, tag, notag, group, nogroup, len(res["events"])))
 
         self.db.insertLastReceivedId(_client, res['lastid'])
-        logging.debug("lastid inserting: %s" % {'lastid': res['lastid'], 'client' : _client})
 
         return res
 
-- 
GitLab