root/branch/ggpolo/umitInventory/DataGrabber.py @ 1431

Revision 1431, 18.2 kB (checked in by ggpolo, 6 years ago)

Huge speed gain on XML insertion into databaseng, including insertion on Inventory and calculating changes.

Line 
1# Copyright (C) 2007 Insecure.Com LLC.
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
20import datetime
21
22from umitCore.Paths import Path
23
24from umitInventory.Calendar import mdays
25from umitInventory.Calendar import isleap
26#from umitInventory.TLBase import view_kind
27
28from umitDB.Connection import ConnectDB
29from umitDB.InventoryChanges import ChangesRetrieve
30
31umitdb = Path.umitdb_ng
32
33DATA_GRAB_MODES = { "yearly_sum": "changes_in_year",
34                    "monthly_sum": "changes_in_month",
35                    "daily_sum": "changes_in_day",
36                    "hourly_sum": "changes_in_hour",
37                    "category": "changes_by_category"
38                }
39           
40class DataGrabber(ConnectDB, ChangesRetrieve):
41    """
42    Grab data from Inventories or a single host for an Inventory, for a time
43    range and format it to be used in Timeline.
44    """
45   
46    def __init__(self, calendar, inventory=None, hostaddr=None):
47        ConnectDB.__init__(self, umitdb)
48        ChangesRetrieve.__init__(self, self.conn, self.cursor)
49
50        self.calendar = calendar
51        self.inventory = inventory
52        self.hostaddr = hostaddr
53       
54       
55    def get_categories(self):
56        """
57        Get all changes categories in database.
58        """
59        categories = { }
60
61        self.use_dict_cursor()
62       
63        # build categories dict
64        for category in self.get_categories_id_name():
65            categories[category['pk']] = (True, category['name'])
66           
67        self.use_standard_cursor()
68
69        return categories
70
71
72    def standard_sum_filter(self):
73        """
74        Standard filter to use when we are grabbing data in Changes Sum kind.
75        """
76        #return {0: (True, view_kind["sum"])}
77        return {0: (True, "Changes Sum")} 
78   
79   
80    def load_changes_for_timerange(self, start, end):
81        """
82        Load changes from database for a timerange.
83        """
84
85       
86    def count_changes_for_timerange(self, start, end):
87        """
88        Return number of changes in a timerange.
89        """
90        count = self.timerange_changes_count(start, end)
91       
92        return count
93
94
95    def changes_by_category(self, *args):
96        """
97        Generic function for changes_anything_by_category
98        """
99        start = [ ] # start points
100        changes = { } # changes in a range
101        categories = self.get_categories()
102
103        # grab data
104        for category in categories.keys():
105            # unused is a filter that we will discard, it is a filter
106            # for Changes Sum, but we will return a filter by category.
107            #unused, cmax, cstart, \
108            unused, cstart, \
109            cevts = self.changes_for_categoryid(category, *args)
110           
111            # add new start point to start list
112            start.extend(cstart)
113
114            # if changes is empty, set initial values to it
115            if not changes:
116                changes = cevts
117                continue
118           
119            # merge lists
120            for key, value in cevts.items():
121
122                cur_list = changes[key]
123                [cur_list[indx].extend(i) for indx, i in enumerate(value)]
124                changes[key] = cur_list
125
126        # decrement by one each key in categories dict, so it follows filter
127        # format used in other places. (0 .. n)
128        c_new = { }
129        for key, values in categories.items():
130            c_new[key - 1] = values
131
132        return c_new, start, changes
133
134         
135    def changes_for_categoryid(self, category, *args):
136        """
137        Generic function for changes_anything_for_categoryid
138        """
139        return self.changes_in_range(category, *args)
140   
141   
142    def changes_in_range(self, category=None, *args):
143        """
144        Generic function for changes_anything
145        """
146        if len(args) == 1: # yearly
147            return self.changes_in_year(args[0], category)
148        elif len(args) == 2: # monthly
149            return self.changes_in_month(args[0], args[1], category)
150        elif len(args) == 3: # daily
151            return self.changes_in_day(args[0], args[1], args[2], category)
152        elif len(args) == 4: # hourly
153            return self.changes_in_hour(args[0], args[1], args[2], args[3], 
154                                        category)
155        else:
156            raise Exception("Invalid number of parameters especified")
157       
158       
159    """
160    Follows changes_in_range especific methods, I plan making them
161    generic too.
162    """
163   
164   
165    def changes_in_year(self, year, category=None):
166        """
167        Gets changes per "week" in an entire year.
168        """   
169        if isleap(year):
170            mdays[2] = 29
171        else:
172            mdays[2] = 28
173       
174        # get last amount of events in past year, or, better:
175        # amount of events that occuried in (year - 1) at December, from
176        # numberOfDaysInDecember / 2 + (numberOfDaysInDecember / 4) till
177        # final of month.
178       
179        if year == self.calendar.year_range[0]:
180            start_value = 0
181           
182        else:
183            half = mdays[12] / 2
184            quarter = half / 2
185            start = datetime.datetime(year - 1, 12, quarter + half)
186            end = datetime.datetime(year, 1, 1)
187       
188            start_value = self.timerange_changes_count_generic(start, end,
189                                                               category,
190                                                               self.inventory,
191                                                               self.hostaddr)
192
193        # get events for year
194        year_events = { }
195       
196        for m in range(12):
197            half = (mdays[m + 1] / 2) + 1
198            quarter = (half / 2)
199           
200            # months with 31 or 30 days:
201            # half = (31/2) + 1 = 16
202            # quarter = 8
203            # will grab 1 -> 8, 8 -> 16, 16 -> 24, 24 -> end month
204            # month with 28 or 29 days:
205            # half = (29/2) + 1 = 15
206            # quarter = 7
207            # will grab 1 -> 7, 7 -> 15, 15 -> 22, 22 -> end month
208           
209            days = (1, quarter, half, half + quarter, 1)
210           
211            mcount = [ ]
212
213            for i in range(len(days) - 1):
214                start = datetime.datetime(year, m + 1, days[i])
215               
216                if i == len(days) - 2:
217                    dyear = year
218                    dmonth = m + 2
219                    if m == 11:
220                        dyear += 1
221                        dmonth = 1
222                       
223                    end = datetime.datetime(dyear, dmonth, days[i + 1])
224                else:
225                    end = datetime.datetime(year, m + 1, days[i + 1])
226               
227                count = self.timerange_changes_count_generic(start, end,
228                                                             category,
229                                                             self.inventory,
230                                                             self.hostaddr)
231
232                mcount.append([count, ])
233           
234            year_events[m] = mcount
235       
236
237        return self.standard_sum_filter(), (start_value, ), year_events
238
239
240    def changes_in_month(self, year, month, category=None):
241        """
242        Get changes in a month.
243        """
244        month_events = { }
245
246        if isleap(year) and month == 2: # month range from 1 to 12
247            mdays[2] = 29
248        else:
249            mdays[2] = 28
250           
251        # get last amount of events in past month, or, better:
252        # amount of events that occuried in (month - 1) at last day, from
253        # 12 PM to 23:59 PM
254        self.calendar.dryrun = True
255        self.calendar.dec_date(1) # 1 indicates it is a month decrement
256        prev_date = self.calendar.temp # what changes were needed to decrement
257        self.calendar.dryrun = False
258   
259        prev_year = year
260        prev_month = month
261       
262        for key, value in prev_date.items():
263            if key == "year":
264                prev_year = value
265            elif key == "month":
266                prev_month = value
267
268        month_range = self.calendar.get_monthrange(prev_year, prev_month)[1]
269        start = datetime.datetime(prev_year, prev_month, month_range, 12)
270        end = datetime.datetime(year, month, 1)
271       
272        start_value = self.timerange_changes_count_generic(start, end,
273                                                           category,
274                                                           self.inventory,
275                                                           self.hostaddr)
276   
277        for day in range(mdays[month]):
278            day_count = [ ]
279
280            # for each day, grab data for 0 AM .. 11:59 AM, 12 PM .. 23:59 PM
281            start = datetime.datetime(year, month, day + 1)
282            end = datetime.datetime(year, month, day + 1, 12)
283
284            count1 = self.timerange_changes_count_generic(start, end,
285                                                          category,
286                                                          self.inventory,
287                                                          self.hostaddr)
288
289            start = datetime.datetime(year, month, day + 1, 12)
290           
291            dyear = year
292            dmonth = month
293            dday = day
294
295            if day == mdays[month] - 1:
296                self.calendar.dryrun = True
297                self.calendar.inc_date(1)
298                next_date = self.calendar.temp
299                self.calendar.dryrun = False
300               
301                dday = 1
302                for key, value in next_date.items():
303                    if key == "year":
304                        dyear = value
305                    elif key == "month":
306                        dmonth = value
307                       
308            else:
309                dday += 2
310           
311            end = datetime.datetime(dyear, dmonth, dday)
312           
313            count2 = self.timerange_changes_count_generic(start, end,
314                                                          category,
315                                                          self.inventory,
316                                                          self.hostaddr)
317
318            day_count.append([count1, ])
319            day_count.append([count2, ])
320            month_events[day] = day_count
321
322
323        return self.standard_sum_filter(), (start_value, ), month_events
324   
325   
326    def changes_in_day(self, year, month, day, category=None):
327        """
328        Get changes in a day.
329        """
330        day_events = { }
331       
332        # get last amount of events in past day, or, better:
333        # amount of events that occuried in (day - 1) at last hour, from
334        # 23:30 to current date 0 hour, 0 minute, 0 second
335        self.calendar.dryrun = True
336        self.calendar.dec_date(2) # 2 indicates it is a day decrement
337        prev_date = self.calendar.temp # what changes were needed to decrement
338        self.calendar.dryrun = False
339       
340        prev_year = year
341        prev_month = month
342        prev_day = day - 1
343
344        for key, value in prev_date.items():
345            if key == "year":
346                prev_year = value
347            elif key == "month":
348                prev_month = value
349            elif key == "day":
350                prev_day = value
351
352        start = datetime.datetime(prev_year, prev_month, prev_day, 23, 30)
353        end = datetime.datetime(year, month, day)
354       
355        start_value = self.timerange_changes_count_generic(start, end,
356                                                           category,
357                                                           self.inventory,
358                                                           self.hostaddr)
359
360        # hour by hour
361        for hour in range(24):
362            hour_count = [ ]
363           
364            # first half hour
365            start = datetime.datetime(year, month, day, hour)
366            end = datetime.datetime(year, month, day, hour, 30)
367           
368            count1 = self.timerange_changes_count_generic(start, end,
369                                                          category,
370                                                          self.inventory,
371                                                          self.hostaddr)
372             
373            # other half
374            start = datetime.datetime(year, month, day, hour, 30)
375           
376            if hour == 23:
377                next_year = year
378                next_month = month
379                next_day = day
380               
381                self.calendar.dryrun = True
382                self.calendar.inc_date(2)
383                next_date = self.calendar.temp
384                self.calendar.dryrun = False
385               
386                for key, value in next_date.items():
387                    if key == "year":
388                        next_year = value
389                    elif key == "month":
390                        next_month = value
391                    elif key == "day":
392                        next_day = value
393                       
394                end = datetime.datetime(next_year, next_month, next_day, 0)
395                   
396            else:
397                end = datetime.datetime(year, month, day, hour + 1)
398           
399            count2 = self.timerange_changes_count_generic(start, end,
400                                                          category,
401                                                          self.inventory,
402                                                          self.hostaddr)
403             
404            hour_count.append([count1, ])
405            hour_count.append([count2, ])
406           
407            day_events[hour] = hour_count
408           
409       
410        return self.standard_sum_filter(), (start_value, ), day_events
411   
412   
413    def changes_in_hour(self, year, month, day, hour, category=None):
414        """
415        Get changes in a especific hour.
416        """
417        hour_events = { }
418       
419        # get last amount of events in past hour, or, better:
420        # amount of events that occuried in (hour - 1) at last minute
421        self.calendar.dryrun = True
422        self.calendar.dec_date(3) # 3 indicates it is an hour decrement
423        prev_date = self.calendar.temp # what changes were needed to decrement
424        self.calendar.dryrun = False
425       
426        prev_year = year
427        prev_month = month
428        prev_day = day
429        prev_hour = hour - 1
430
431        for key, value in prev_date.items():
432            if key == "year":
433                prev_year = value
434            elif key == "month":
435                prev_month = value
436            elif key == "day":
437                prev_day = value
438                prev_hour = 23
439
440        start = datetime.datetime(prev_year, prev_month, prev_day, prev_hour, 
441                                  59)
442        end = datetime.datetime(year, month, day, hour, 0)
443       
444        start_value = self.timerange_changes_count_generic(start, end,
445                                                           category,
446                                                           self.inventory,
447                                                           self.hostaddr)
448
449        # minute by minute
450        for minute in range(60):
451            start = datetime.datetime(year, month, day, hour, minute)
452           
453            if minute == 59:
454                next_year = year
455                next_month = month
456                next_day = day
457                next_hour = hour + 1
458               
459                self.calendar.dryrun = True
460                self.calendar.inc_date(3)
461                next_date = self.calendar.temp
462                self.calendar.dryrun = False
463               
464                for key, value in next_date.items():
465                    if key == "year":
466                        next_year = value
467                    elif key == "month":
468                        next_month = value
469                    elif key == "day":
470                        next_day = value
471                        next_hour = 0
472                       
473                end = datetime.datetime(next_year, next_month, next_day,
474                                        next_hour)
475            else:
476                end = datetime.datetime(year, month, day, hour, minute + 1)
477           
478            count = self.timerange_changes_count_generic(start, end,
479                                                         category,
480                                                         self.inventory,
481                                                         self.hostaddr)
482           
483            hour_events[minute] = [[count, ]]
484           
485       
486        return self.standard_sum_filter(), (start_value, ), hour_events
487   
488
489       
490if __name__ == "__main__":
491    #dg.count_changes_for_timerange(datetime.datetime(2007, 1, 1),
492    #                  datetime.datetime(2007, 1, 31, 23, 59, 59, 999))
493    #lfilter, max_v, start, evts = dg.changes_in_year(2007)
494    #print max_v, start, evts
495   
496    # some methods from ChangesRetrieve
497    #print dg.get_categories_id_name()
498    #print dg.get_categories_name()
499    #print dg.get_category_id_by_name('Fingerprint')
500    #print dg.get_category_name_by_id(1)
501
502    #max_v, start, evts = dg.changes_for_categoryid(2007, 1)
503    #print max_v, start, evts
504
505    from umitInventory.Calendar import startup_calendar_opts
506    from umitInventory.Calendar import CalendarManager
507
508    start = startup_calendar_opts()
509    cal = CalendarManager(**start)
510
511    lfilter, max_v, start, evts = DataGrabber(cal).changes_in_year(2007)
512    print lfilter, max_v, start, evts[6]
513
514    #lfilter, max, start, evts = DataGrabber(cal).changes_by_category(2007, 7)
515    lfilter, max_v, start, evts = DataGrabber(cal).changes_in_month(2007, 7)
516
517    for key, value in evts.items():
518        print key, value
519
Note: See TracBrowser for help on using the browser.