root/branch/NetworkInventory/umit/db/Search.py @ 4252

Revision 4252, 10.9 kB (checked in by gpolo, 4 years ago)

Merged revisions 4240-4248 via svnmerge from
http://svn.umitproject.org/svnroot/umit/trunk

........

r4240 | gpolo | 2009-03-02 13:15:33 -0300 (Mon, 02 Mar 2009) | 1 line


Restructuring umit, second step. See ticket #229.

........

r4241 | gpolo | 2009-03-02 13:19:09 -0300 (Mon, 02 Mar 2009) | 1 line


Removing old directories

........

r4242 | gpolo | 2009-03-02 13:19:42 -0300 (Mon, 02 Mar 2009) | 1 line


Removed umitInterfaceEditor now

........

r4243 | gpolo | 2009-03-02 13:21:20 -0300 (Mon, 02 Mar 2009) | 1 line


Fixed some remaining old umitCore imports

........

r4244 | gpolo | 2009-03-02 15:26:14 -0300 (Mon, 02 Mar 2009) | 1 line


Renamed UMIT_CONFIG_DIR to UMIT_CFG_DIR so the unix installer doesn't replace its content when installing umit.

........

r4245 | gpolo | 2009-03-02 15:50:36 -0300 (Mon, 02 Mar 2009) | 1 line


Adjusted installers for the new structure. This concludes ticket #229.

........

r4246 | gpolo | 2009-03-02 15:59:02 -0300 (Mon, 02 Mar 2009) | 1 line


Removed unused shell scripts.

........

r4247 | gpolo | 2009-03-02 16:03:54 -0300 (Mon, 02 Mar 2009) | 1 line


Updated version_update.py and ran it.

........

r4248 | gpolo | 2009-03-02 16:06:01 -0300 (Mon, 02 Mar 2009) | 1 line


test_paths.sh has been abandoned too, gone now.

........

Line 
1# Copyright (C) 2007 Adriano Monteiro Marques
2#
3# Author:  Guilherme Polo <ggpolo@gmail.com>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18# USA
19
20from umit.db.Utils import log_debug
21from umit.db.Connection import ConnectDB
22from umit.db.Retrieve import CompositeRetrieve
23
24from umit.core.I18N import _
25
26debug = log_debug('umit.db.Search')
27
28change_text = (_("change"), _("changes"))
29port_text = (_("port"), _("ports"), _("service"))
30comparison = ("<", ">", "==", ">=", "<=", "!=")
31
32def perform_comparison(ports, compare, decider):
33    """
34    Compare ports against decider using especified comparation.
35    """
36    decider = int(decider)
37
38    # ports are numbered in ascendent order.
39    for port in ports:
40        if compare == '>':
41            if decider <= port[0]:
42                return True
43        if compare == '<':
44            if decider < port[0]:
45                return False
46            elif decider > port[0]:
47                return True
48        if compare == '!=':
49            if port[0] == decider:
50                return False
51        if compare == '==':
52            if port[0] == decider:
53                return True
54        if compare == '>=':
55            if port[0] >= decider:
56                return True
57        if compare == '<=':
58            if decider < port[0]:
59                if decider == port[0]:
60                    return True
61                return False
62            return True
63
64    if compare == '!=':
65        return True
66
67    return False
68
69
70class SearchDB(ConnectDB, CompositeRetrieve):
71    """
72    Performs search on database.
73    """
74    search_meths = {"ports": "port_search", "changes": "changes_search"}
75
76
77    def __init__(self, db):
78        """
79        Expects an umit database.
80        """
81        ConnectDB.__init__(self, db)
82        CompositeRetrieve.__init__(self, self.conn, self.cursor)
83
84
85    def search(self, host_id, query):
86        """
87        Convenience method. Performs searches for host_id.
88        """
89        likely_category = query.split()[0]
90        meth = None
91
92        if likely_category in port_text:
93            meth = self.search_meths["ports"]
94        elif likely_category in change_text:
95            meth = self.search_meths["changes"]
96
97        if meth:
98            res = getattr(self, meth)(host_id, query)
99            if res:
100                return res
101
102        if self.search_for_hostname_for_host_from_db(host_id, query):
103            return _("Hostname")
104
105        if self.search_for_osmatch_for_host_from_db(host_id, query):
106            return _("OS Match")
107
108        if self.search_for_osclasses_for_host_from_db(host_id, query):
109            return _("OS Classes")
110
111        if self.search_for_mac_for_host_from_db(host_id, query):
112            return _("MAC")
113
114        if self.search_for_fingerprint_for_host_from_db(host_id, query):
115            return _("Fingerprint")
116
117        # if I'm still here, no results were returned. I will try to do a
118        # port search then. Situation where this may happen:
119        # - Person searching doesnt know about port search syntax, so it does
120        #   a search like "mysql". The correct way would be: "service mysql".
121        res = self.port_search(host_id, port_text[0] + " " + query)
122        if res:
123            return res
124
125
126    def port_search(self, host_id, query):
127        """
128        Search for ports for host_id.
129        """
130        debug("Searching under Ports for %s for host_id %d..", query, host_id)
131        # a port search query is expected to be something like:
132        #  <port_text> <comparison OR Nothing> <something>
133
134        query = query.split()
135        if len(query) < 2 or (not query[0] in port_text):
136            # bad syntax for port search
137            return None
138
139        looking_for = query[1]
140        compare = None
141        if len(query) == 3:
142            # assuming second item is a comparion item
143            if query[1] in comparison:
144                # valid comparison especified
145                compare = query[1]
146
147            looking_for = query[2]
148
149
150        results = ''
151        portnumber = False
152
153        try:
154            int(looking_for)
155            portnumber = True
156        except ValueError:
157            portnumber = False
158            # will perform porttext search
159
160        if portnumber:
161            # search for port with number in looking_for
162            if compare:
163                self.cursor.execute("SELECT port.portid FROM port "
164                    "JOIN _host_port ON (_host_port.fk_port=port.pk) "
165                    "WHERE _host_port.fk_host=?", (host_id, ))
166                search = self.cursor.fetchall()
167                search = perform_comparison(search, compare, looking_for)
168
169            else:
170
171                self.cursor.execute("SELECT port.portid FROM port "
172                    "JOIN _host_port ON (_host_port.fk_port=port.pk) "
173                    "WHERE _host_port.fk_host=? AND port.portid LIKE ?",
174                        (host_id, '%'+looking_for+'%'))
175                search = self.cursor.fetchall()
176
177            if search:
178                results = _("Port number")
179        else:
180            # search for some text
181            pdata = self.get_portid_and_fks_for_host_from_db(host_id)
182            for pd in pdata:
183                res = self._search_port_text_for_pdata(pd[1], looking_for)
184                if res:
185                    results = res
186                    break
187
188        return results
189
190
191    def _search_port_text_for_pdata(self, service_info_id, query):
192        """
193        """
194        bquery = '%' + query + '%'
195
196        # Im supposing service name is more likely to be queried than
197        # service info. Also, there is just one field to compare against query
198        # in service_name.
199        service_name = self.cursor.execute("SELECT name FROM service_name "
200            "JOIN service_info ON "
201            "(service_info.fk_service_name=service_name.pk) "
202            "WHERE service_info.pk=? AND name LIKE ?", (service_info_id,
203                bquery)).fetchall()
204        if service_name:
205            return _("Service name")
206
207        service_info = self.cursor.execute("SELECT product, version, "
208            "extrainfo FROM service_info WHERE service_info.pk=? AND "
209            "(product LIKE ? OR version LIKE ? or extrainfo LIKE ?)",
210                (service_info_id, bquery, bquery, bquery)).fetchall()
211        if service_info:
212            return _("Service info")
213
214
215    def changes_search(self, host_id, query):
216        """
217        Search in _inventory_changes for something like query for host_id.
218        """
219        debug("Searching under Inventory changes for %s for host_id %d..",
220                query, host_id)
221
222        query = query.split()
223        if len(query) < 2 or (not query[0] in change_text):
224            # bad syntax for changes search
225            return None
226
227        address_id = self.get_address_pk_for_host_from_db(host_id)
228
229        looking_for = query[1:]
230
231        bquery = '%' + ' '.join(looking_for) + '%'
232       
233        self.cursor.execute("SELECT pk FROM _inventory_changes "
234            "WHERE fk_address=? AND short_description LIKE ?", (address_id,
235                bquery))
236        results = self.cursor.fetchall()
237
238        if results:
239            return _("Changes")
240
241
242    def search_for_hostname_for_host_from_db(self, host_id, query):
243        """
244        Search for hostnames like query for host_id.
245        """
246        debug("Searching for hostname %s for host_id %d", query, host_id)
247
248        hostname = self.cursor.execute("SELECT hostname.name FROM hostname "
249            "JOIN _host_hostname ON (_host_hostname.fk_hostname=hostname.pk) "
250            "WHERE _host_hostname.fk_host=? AND hostname.name LIKE ?",
251                (host_id, '%' + query + '%')).fetchall()
252
253        if hostname:
254            return True
255
256
257    def search_for_osmatch_for_host_from_db(self, host_id, query):
258        """
259        Search for osmatch like query for host_id.
260        """
261        debug("Searching under OS Match for %s for host_id %d..",
262                query, host_id)
263
264        match = self.cursor.execute("SELECT name FROM osmatch "
265            "WHERE fk_host=? AND name LIKE ?", (host_id,
266                '%' + query + '%')).fetchall()
267        if match:
268            return True
269
270
271
272    def search_for_osclasses_for_host_from_db(self, host_id, query):
273        """
274        Search for osclasses like query for host_id.
275        """
276        debug("Searching under OS Classes for %s for hots_id %d",
277                query, host_id)
278
279        bquery = '%' + query + '%'
280       
281        classes = self.cursor.execute("SELECT osclass.accuracy, osgen.gen, "
282            "osfamily.family, osvendor.vendor, ostype.type FROM osclass "
283            "JOIN osgen ON (osclass.fk_osgen = osgen.pk) "
284            "JOIN osfamily ON (osclass.fk_osfamily = osfamily.pk) "
285            "JOIN osvendor ON (osclass.fk_osvendor = osvendor.pk) "
286            "JOIN ostype ON (osclass.fk_ostype = ostype.pk) "
287            "WHERE osclass.fk_host = ? AND (osgen.gen LIKE ? OR "
288            "osfamily.family LIKE ? OR osvendor.vendor LIKE ? OR "
289            "ostype.type LIKE ?)", (host_id, bquery, bquery, bquery,
290                bquery)).fetchall()
291
292        if classes:
293            return True
294
295
296    def search_for_mac_for_host_from_db(self, host_id, query):
297        """
298        Search for MAC like query for host_id.
299        """
300        debug("Searching MAC address like %s for host_id %d", query, host_id)
301
302        fk_address = self.cursor.execute("SELECT fk_address "
303            "FROM _host_address WHERE fk_host = ?", (host_id, )).fetchall()
304
305        mac = None
306        for fk in fk_address:
307            mac = self.cursor.execute("SELECT address FROM address "
308                "WHERE type = 'mac' AND pk = ? AND address LIKE ?", (fk[0],
309                    '%' + query + '%')).fetchone()
310            if mac:
311                return True
312
313
314    def search_for_fingerprint_for_host_from_db(self, host_id, query):
315        """
316        Search for query in fingerprint table for host_id.
317        """
318        debug("Searching for Fingerprint info like %s for host_id %d",
319                query, host_id)
320
321        bquery = '%' + query + '%'
322        self.cursor.execute("SELECT tcp_sequence_class, "
323            "tcp_ts_sequence_class, ip_id_sequence_class "
324            "FROM fingerprint_info WHERE fk_host=? AND "
325            "(tcp_sequence_class LIKE ? OR tcp_ts_sequence_class LIKE ? OR "
326            "ip_id_sequence_class LIKE ?)", (host_id, bquery, bquery, bquery))
327        fp = self.cursor.fetchall()
328        if fp:
329            return True
Note: See TracBrowser for help on using the browser.