Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

vigiboard / vigiboard / controllers / vigiboardrequest.py @ 02503aef

History | View | Annotate | Download (14.7 KB)

1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""Gestion de la requête, des plugins et de l'affichage du Vigiboard"""
4

    
5
from vigiboard.model import Events, Host, Service, \
6
        HostGroups, ServiceGroups, EventHistory
7
from tg import tmpl_context, url, config
8
from vigiboard.model import DBSession
9
from sqlalchemy import not_ , and_ , asc , desc
10
from tw.jquery.ui_dialog import JQueryUIDialog
11
from vigiboard.widgets.edit_event import EditEventForm , SearchForm
12
from vigiboard.controllers.userutils import get_user_groups
13
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
14
from pylons.i18n import ugettext as _
15

    
16
class VigiboardRequest():
17
    
18
    """
19
    Classe gérant la génération de la requête finale,
20
    le préformatage des évènements et celui des historiques
21
    """
22

    
23
    def __init__(self):
24

    
25
        """
26
        Initialisation de toutes les variables nécessaires: Liste des groupes de
27
        l'utilisateur, les classes à appliquer suivant la sévérité, les
28
        différentes étapes de la génération de la requête et la liste des
29
        plugins appliqués.
30
        """
31

    
32
        self.user_groups = get_user_groups()
33
        self.bouton_severity = { 0: 'Minor', 1: 'Minor', 2: 'Minor',
34
                3: 'Minor', 4: 'Minor', 5: 'Minor', 6: 'Major', 7: 'Critical' }
35
        self.class_severity = { 0: 'None', 1: 'None', 2: 'None', 3: 'None',
36
                4: 'None', 5: 'Minor', 6: 'Major', 7: 'Critical' }
37
        self.severity = { 0: _('None'), 1: _('OK'), 2: _('Suppressed'),
38
                3: _('Initial'), 4: _('Maintenance'), 5: _('Minor'),
39
                6: _('Major'), 7: _('Critical') }
40

    
41
        self.class_ack = {'Acknowledged': 'Ack', 'None': '', 'AAClosed': 'Ack'}
42

    
43
        self.generaterq = False
44
        self.table = [Events]
45
        self.join = [( Host, Events.hostname == Host.name ),
46
                ( Service, Events.servicename == Service.name ),
47
                ( HostGroups , Host.name == HostGroups.hostname ),
48
                ( ServiceGroups , Service.name == ServiceGroups.servicename )
49
                ]
50
        self.outerjoin = []
51
        self.filter = [HostGroups.groupname.in_(self.user_groups),
52
                 ServiceGroups.groupname.in_(self.user_groups),
53
                 not_(and_(Events.active == False,
54
                     Events.status == 'AAClosed')),
55
                 Events.timestamp_active != None#,
56
                 #not_(Events.timestamp_active.like('0000-00-00 00:00:00'))
57
                 ]
58
        self.orderby = [desc(Events.status),
59
                                desc(Events.active),
60
                                desc(Events.severity),
61
                                asc(Events.hostname),
62
                                desc(Events.timestamp)]
63
        self.groupby = []
64
        self.plugin = []
65
        self.events = []
66
        self.idevents = []
67
        self.hist = []
68
        self.req = DBSession
69

    
70
    def add_plugin(self, *argv):
71
        
72
        """
73
        Ajout d'un plugin, on lui prélève ses ajouts dans la requête
74
        """
75
        for i in argv :
76
            if isinstance(i, VigiboardRequestPlugin):
77
                if i.table :
78
                    self.add_table(*i.table)
79
                if i.join :
80
                    self.add_join(*i.join)
81
                if i.outerjoin :
82
                    self.add_outer_join(*i.outerjoin)
83
                if i.filter :
84
                    self.add_filter(*i.filter)
85
                if i.groupby :    
86
                    self.add_group_by(*i.groupby)
87
                if i.orderby :
88
                    self.add_order_by(*i.orderby)
89
                self.plugin.append(i)
90

    
91
    def generate_request(self):
92
        
93
        """
94
        Génération de la requête avec l'ensemble des données stockées
95
        et la place dans la variable rq de la classe
96
        """
97
        for plug in config['vigiboard_plugins']:
98
            try:
99
                mypac = __import__(
100
                    'vigiboard.controllers.vigiboard_plugin.' +\
101
                            plug[0],globals(), locals(), [plug[1]],-1)
102
                self.add_plugin(getattr(mypac,plug[1])())
103
            except:
104
                raise
105
        
106
        # query et join ont besoin de referrence
107
        self.req = self.req.query(*self.table)
108
        self.req = self.req.join(*self.join)
109

    
110
        # le reste, non
111
        for i in self.outerjoin:
112
            self.req = self.req.outerjoin(i)
113
        for i in self.filter:
114
            self.req = self.req.filter(i)
115
        for i in self.groupby:
116
            self.req = self.req.group_by(i)
117
        for i in self.orderby:
118
            self.req = self.req.order_by(i)
119

    
120
    def num_rows(self):
121

    
122
        """
123
        Retourne le nombre de lignes de la requête.
124
        Si celle-ci n'est pas encore générée, on le fait.
125

126
        @return: Nombre de ligne
127
        """
128

    
129
        if not self.generaterq :
130
            self.generate_request()
131
            self.generaterq = True
132
        return self.req.count()
133

    
134
    def add_table(self, *argv):
135
        
136
        """
137
        Ajoute une ou plusieurs tables/élément d'une table à
138
        la requête.
139

140
        @param argv: Liste des tables à ajouter
141
        """
142
        
143
        #On vérifi qu'il n'y a pas de doublons dans la liste des
144
        #tables finale
145
        
146
        for i in argv :
147
            for j in self.table:
148
                if str(i) == str(j):
149
                    break
150
            self.table.append(i)
151

    
152
    def add_join(self, *argv):
153
        
154
        """
155
        Ajoute une ou plusieurs jointures à
156
        la requête.
157

158
        @param argv: Liste des jointures à ajouter
159
        """
160
        
161
        #On vérifi qu'il n'y a pas de doublons dans la liste des
162
        #jointures finale
163
        
164
        for i in argv:
165
            for j in self.join:
166
                if str(i) == str(j):
167
                    break
168
            self.join.append(i)
169

    
170
    def add_outer_join(self, *argv):
171
        
172
        """
173
        Ajoute une ou plusieurs jointures externes à
174
        la requête.
175

176
        @param argv: Liste des jointures externes à ajouter
177
        """
178
        
179
        #On vérifi qu'il n'y a pas de doublons dans la liste des
180
        #jointures externes finale
181
        
182
        for i in argv:
183
            for j in self.outerjoin:
184
                if str(i) == str(j):
185
                    break
186
            self.outerjoin.append(i)    
187

    
188
    def add_filter(self, *argv):
189

    
190
        """
191
        Ajoute un ou plusieurs filtres à la requête.
192

193
        @param argv: Liste des filtres à ajouter
194
        """
195
        
196
        #On vérifi qu'il n'y a pas de doublons dans la liste des
197
        #filtres finale
198
        
199
        for i in argv:
200
            for j in self.filter:
201
                if str(i) == str(j):
202
                    break
203
            self.filter.append(i)
204

    
205
    def add_group_by(self, *argv):
206

    
207
        """
208
        Ajoute un ou plusieurs groupements à la requête.
209

210
        @param argv: Liste des groupements à ajouter
211
        """
212
        
213
        #On vérifi qu'il n'y a pas de doublons dans la liste des
214
        #groupements finale
215
        
216
        for i in argv:
217
            for j in self.groupby:
218
                if str(i) == str(j):
219
                    break
220
            self.groupby.append(i)
221

    
222
    def add_order_by(self, *argv):
223

    
224
        """
225
        Ajoute un ou plusieurs orders à la requête.
226

227
        @param argv: Liste des ordres à ajouter
228
        """
229
        
230
        #On vérifi qu'il n'y a pas de doublons dans la liste des
231
        #ordres finale
232
        
233
        for i in argv:
234
            for j in self.orderby:
235
                if str(i) == str(j):
236
                    break
237
            self.orderby.append(i)
238

    
239
    def format_events_img_statu (self, event):
240
        
241
        """
242
        Suivant l'état de l'évènement, retourne la classe à appliquer
243
        à l'image indiquant si l'évènement est pris en compte ou non.
244

245
        @param event: l'évènement à analyser
246

247
        @return: Dictionnaire représentant la classe à appliquer
248
        """
249

    
250
        if event.active and event.status == 'AAClosed':
251
            return { 'src': url('/images/crossed.png') }
252
        elif event.status == 'Acknowledged' :
253
            return { 'src': url('/images/checked.png') }
254
        else:
255
            return None
256

    
257
    def format_events(self, first_row, last_row):
258
        
259
        """
260
        Formate la réponse de la requête et y applique les plugins
261
        pour un affichage simple du résultat par Genshi.
262
        On génère une liste de liste, chaqu'une étant la description de
263
        l'affichage pour un évènement donné.
264

265
        @param first_row: Indice de début de la liste des évènements
266
        @param last_row: Indice de fin de la liste des évènements
267
        """
268
        
269
        # Si la requête n'est pas générée, on le fait
270
        if not self.generaterq :
271
            self.generate_request()
272
            self.generaterq = True
273

    
274
        # Liste des éléments pour la tête du tableau
275

    
276
        lst_title = ['', _('Date<br />[Duration]'), '#', _('Host'),
277
                _('Service Type<br />Service Name'), _('Output')]
278
        lst_title.extend([plug.name for plug in self.plugin])
279
        lst_title.extend(['[T T]', ''])
280
        
281
        events = [lst_title]
282
        i = 0
283
        class_tr = ['odd', 'even']
284
        ids = []
285
        for req in self.req[first_row : last_row]:
286

    
287
            # Si il y a plus d'un élément dans la liste des tables,
288
            # rq devient une liste plutôt que d'être directement la
289
            # table souhaité
290
            
291
            if isinstance(req, Events) :
292
                event = req
293
            else :
294
                event = req[0]
295
            ids.append(event.idevent)
296

    
297
            # La liste pour l'évènement actuel comporte dans l'ordre :
298
            #   L'évènment en lui même
299
            #   La classe à appliquer sur la ligne (permet d'alterner les
300
            #       couleurs suivant les lignes)
301
            #   La classe pour la case comportant la flèche de détails
302
            #   La classe pour la date, l'occurrence et l'édition
303
            #   L'image a affiche pour la flèche de détails
304
            #   Une liste (une case par plugin) de ce que le plugin souhaite
305
            #       afficher en fonction de l'évènement
306

    
307
            if event.active :
308
                events.append([
309
                    event,
310
                    {'class': class_tr[i%2]},
311
                    {'class' : self.bouton_severity[event.severity] + \
312
                            self.class_ack[event.status]},
313
                    {'class' : self.bouton_severity[event.severity] + \
314
                            self.class_ack[event.status] },
315
                    {'src' : '/images/%s2.png' % \
316
                            self.bouton_severity[event.severity].upper()},
317
                    self.format_events_img_statu(event),
318
                    [[j.__show__(req), j.style] for j in self.plugin]
319
                    ])
320
            else :
321
                events.append([
322
                    event,
323
                    {'class': class_tr[i%2]},
324
                    {'class' : self.bouton_severity[event.severity] + \
325
                            self.class_ack[event.status] },
326
                    {'class' : 'Cleared' + self.class_ack[event.status] },
327
                    {'src' : '/images/%s2.png' % \
328
                            self.bouton_severity[event.severity].upper()},
329
                    self.format_events_img_statu(event),
330
                    [[j.__show__(req), j.style] for j in self.plugin]
331
                    ])
332
            i = i + 1
333

    
334
        # On sauvegarde la liste précédemment créée puis rempli
335
        # le TmplContext
336

    
337
        self.events = events
338
        self.idevents = ids
339

    
340
    def format_history (self):
341
        
342
        """
343
        Formate les historiques correspondant aux évènements sélectionnés
344
        pour un affichage simple du résultat par Genshi.
345
        On génère une liste de liste, chaqu'une étant la description de l'affichage pour un
346
        historique donné.
347
        """
348

    
349
        history = DBSession.query(EventHistory
350
                ).filter(EventHistory.idevent.in_(self.idevents)
351
                ).order_by(desc(EventHistory.timestamp)
352
                ).order_by(desc(EventHistory.idhistory))
353

    
354
        if history.count() == 0:
355
            self.hist = []
356
            return
357
        hists = []
358
        i = 0
359
        class_tr = ['odd', 'even']
360
        hostname = self.events[1][0].hostname
361
        servicename = self.events[1][0].servicename
362

    
363
        for hist in history :
364

    
365
            # La liste pour l'historique actuel comporte dans l'ordre :
366
            #   Son identifiant
367
            #   Son nom d'hôte
368
            #   Son nom de service
369
            #   Le moment où il a été généré
370
            #   Qui l'a généré
371
            #   Le type d'action qui a été appliqué
372
            #   La sévérité de l'action si besoin est
373
            #   Le détail de l'action
374
            #   La classe à appliquer à la ligne (permet d'alterner
375
            #       les couleurs)
376
            #   La classe de la sévérité s'il y a
377

    
378
            if hist.value :
379
                hists.append([
380
                    hist.idhistory,
381
                    hostname,
382
                    servicename,
383
                    hist.timestamp,
384
                    hist.username,
385
                    hist.type_action,
386
                    self.severity[min(int(hist.value),7)],
387
                    hist.text,
388
                    {'class' : class_tr[i%2]},
389
                    {'class':self.class_severity[min(int(hist.value),7)]}
390
                ])
391
            else:
392
                hists.append([
393
                    hist.idhistory,
394
                    hostname,
395
                    servicename,
396
                    hist.timestamp,
397
                    hist.username,
398
                    hist.type_action,
399
                    self.severity[0],
400
                    hist.text,
401
                    {'class' : class_tr[i%2]},
402
                    {'class':self.class_severity[0]}
403
                ])    
404
            i = i + 1
405
        
406
        self.hist = hists
407

    
408
    def generate_tmpl_context(self):
409
        
410
        """
411
        Génère et peuple la variable tmpl_context avec les Dialogs et
412
        formulaires nécessaire au fonctionnement de Vigiboard
413
        """
414

    
415
        # Dialogue d'édition
416
        tmpl_context.edit_event_form = EditEventForm('edit_event_form',
417
                action=url('/update'))
418
        tmpl_context.edit_eventdialog = JQueryUIDialog(id='Edit_EventsDialog',
419
                autoOpen=False,title=_('Edit Event'))
420
    
421
        # Dialogue de recherche
422
        tmpl_context.search_form = SearchForm('search_form',
423
                action=url('/'))
424
        tmpl_context.searchdialog = JQueryUIDialog(id='SearchDialog',
425
                autoOpen=False,title=_('Search Event'))
426
        
427
        # Dialogue de détail d'un évènement
428
        tmpl_context.historydialog = JQueryUIDialog(id='HistoryDialog',
429
                autoOpen=False,title=_('History'))