Project

General

Profile

Revision 15b98053

ID15b9805385ec091cfcda1728d0cf3d5860e1e236
Parent 6f3833d6
Child 07b62a01

Added by Francois POIROTTE over 14 years ago

Modification de la gestion des plugins dans VigiBoard : toutes les colonnes
affichées dans le tableau des événements de VigiBoard sont des plugins.

NOTE : Certains tests unitaires sont encore cassés suite au changement, en
attendant que je comprenne mieux ce qui cloche.

Les plugins sont définis grâce à un fichier Python qui contient une classe
(éventuellement "vide") qui hérite de VigiboardRequestPlugin et un fichier
de template dans les thèmes. Le template contient 3 macros Genshi appelées
à des moments différents de la construction de la page HTML.
Voir le plugin "test" pour la documentation sur les différents codes.

Autres modifications moins importantes :
Renommage du plugin "shn" en "hls" pour la cohérence des termes (nom de
"variables" en anglais).
Simplification de l'interface de la classe python qui gère les plugins.
Transformation du dialogue d'historique en plugin (impacte la méthode
"history_dialog" du RootController de VigiBoard et les tests associés).

git-svn-id: https://vigilo-dev.si.c-s.fr/svn@2127 b22e2e97-25c9-44ff-b637-2e5ceca36478

View differences:

vigiboard/config/app_cfg.py
78 78

  
79 79
# Plugins to use
80 80
base_config['vigiboard_plugins'] = [
81
    ['shn', 'PluginSHN'],
81
    ('history', 'PluginHistory'),
82
    ('date', 'PluginDate'),
83
    ('priority', 'PluginPriority'),
84
    ('occurrences', 'PluginOccurrences'),
85
    ('servicename', 'PluginServicename'),
86
    ('hostname', 'PluginHostname'),
87
    ('output', 'PluginOutput'),
88
    ('hls', 'PluginHLS'),
89
    ('tt', 'PluginTroubleTicket'),
90
    ('status', 'PluginStatus'),
91

  
92
    # Le plugin PluginId peut servir pour débuguer VigiBoard.
93
    # En production, mieux vaut le désactiver car il expose
94
    # des données d'un niveau assez bas dans l'interface.
95
#    ('id', 'PluginId'),
82 96
]
83 97

  
84 98
base_config['vigiboard_refresh_times'] = (
vigiboard/controllers/root.py
186 186

  
187 187
        return dict(
188 188
            events = aggregates.events,
189
            plugins = get_plugins_instances(),
189 190
            rows_info = {
190 191
                'id_first_row': id_first_row,
191 192
                'id_last_row': id_last_row,
......
200 201
            search = search,
201 202
            refresh_times = config['vigiboard_refresh_times'],
202 203
        )
203
      
204
    @validate(validators={'idcorrevent': validators.Int(not_empty=True)},
205
            error_handler=process_form_errors)
206
    @expose('json')
207
    @require(Any(not_anonymous(), msg=l_("You need to be authenticated")))
208
    def history_dialog(self, idcorrevent):
209
        
210
        """
211
        JSon renvoyant les éléments pour l'affichage de la fenêtre de dialogue
212
        contenant des liens internes et externes.
213
        Pour accéder à cette page, l'utilisateur doit être authentifié.
214

  
215
        @param id: identifiant de l'événement
216
        """
217

  
218
        # Obtention de données sur l'événement et sur son historique
219
        username = request.environ.get('repoze.who.identity'
220
                    ).get('repoze.who.userid')
221

  
222
        username = request.environ['repoze.who.identity']['repoze.who.userid']
223
        events = VigiboardRequest(User.by_user_name(username))
224
        events.add_table(
225
            Event,
226
            events.items.c.hostname,
227
            events.items.c.servicename,
228
        )
229
        events.add_join((CorrEvent, CorrEvent.idcause == Event.idevent))
230
        events.add_join((events.items, 
231
            Event.idsupitem == events.items.c.idsupitem))
232
        events.add_filter(CorrEvent.idcorrevent == idcorrevent)
233

  
234
        # Vérification que au moins un des identifiants existe et est éditable
235
        if events.num_rows() != 1:
236
            flash(_('No access to this event'), 'error')
237
            redirect('/')
238

  
239
        event = events.req[0]
240
        eventdetails = {}
241
        for edname, edlink in \
242
                config['vigiboard_links.eventdetails'].iteritems():
243

  
244
            # Rappel:
245
            # event[0] = priorité de l'alerte corrélée.
246
            # event[1] = alerte brute.
247
            if event.servicename:
248
                service = urllib.quote(event.servicename)
249
            else:
250
                service = None
251
            eventdetails[edname] = edlink[1] % {
252
                'idcorrevent': idcorrevent,
253
                'host': urllib.quote(event.hostname),
254
                'service': service,
255
                'message': urllib.quote(event[0].message),
256
            }
257

  
258
        return dict(
259
                current_state = StateName.value_to_statename(
260
                                    event[0].current_state),
261
                initial_state = StateName.value_to_statename(
262
                                    event[0].initial_state),
263
                peak_state = StateName.value_to_statename(
264
                                    event[0].peak_state),
265
                idcorrevent = idcorrevent,
266
                host = event.hostname,
267
                service = event.servicename,
268
                eventdetails = eventdetails,
269
            )
270 204

  
271 205
    @validate(validators={'idcorrevent': validators.Int(not_empty=True)},
272 206
            error_handler=process_form_errors)
......
298 232
            redirect('/')
299 233
       
300 234
        events.format_events(0, 1)
301
        events.format_history()
235
        history_entries = events.format_history()
302 236
        events.generate_tmpl_context() 
303 237

  
304 238
        return dict(
305 239
            events = events.events,
240
            plugins = get_plugins_instances(),
306 241
            rows_info = {
307 242
                'id_first_row': 1,
308 243
                'id_last_row': 1,
......
311 246
            nb_pages = 1,
312 247
            page = 1,
313 248
            event_edit_status_options = edit_event_status_options,
314
            history = events.hist,
249
            history = history_entries,
315 250
            hist_error = True,
316 251
            plugin_context = events.context_fct,
317 252
            search = {
......
371 306
            redirect('/')
372 307

  
373 308
        events.format_events(0, events.num_rows())
374
        events.format_history()
309
        history_entries = events.format_history()
375 310
        events.generate_tmpl_context()
376 311

  
377 312
        return dict(
378 313
                    events = events.events,
314
                    plugins = get_plugins_instances(),
379 315
                    rows_info = {
380 316
                        'id_first_row': 1,
381 317
                        'id_last_row': 1,
......
384 320
                    nb_pages = 1,
385 321
                    page = 1,
386 322
                    event_edit_status_options = edit_event_status_options,
387
                    history = events.hist,
323
                    history = history_entries,
388 324
                    hist_error = True,
389 325
                    plugin_context = events.context_fct,
390 326
                    search = {
......
410 346
            u'AAClosed'
411 347
        ])}, error_handler=process_form_errors)
412 348
    @require(Any(not_anonymous(), msg=l_("You need to be authenticated")))
413
    def update(self,**krgv):
349
    def update(self, **krgv):
414 350
        """
415 351
        Mise à jour d'un événement suivant les arguments passés.
416 352
        Cela peut être un changement de ticket ou un changement de statut.
......
500 436
        flash(_('Updated successfully'))
501 437
        redirect(request.environ.get('HTTP_REFERER', url('/')))
502 438

  
503

  
504
    @validate(validators={"plugin_name": validators.OneOf(
505
        [i for [i, j] in config.get('vigiboard_plugins', [])])},
506
                error_handler = process_form_errors)
439
    @validate(validators={
440
        "plugin_name": validators.OneOf([i[0] for i \
441
            in config.get('vigiboard_plugins', [])]),
442
        'idcorrevent': validators.Int(not_empty=True),
443
        }, error_handler=process_form_errors)
507 444
    @expose('json')
508 445
    @require(Any(not_anonymous(), msg=l_("You need to be authenticated")))
509 446
    def get_plugin_value(self, idcorrevent, plugin_name, *arg, **krgv):
......
511 448
        Permet de récupérer la valeur d'un plugin associée à un CorrEvent
512 449
        donné via JSON.
513 450
        """
514
        plugins = config['vigiboard_plugins']
515
        if plugins is None:
516
            raise HTTPNotFound()
451
        plugins = config.get('vigiboard_plugins', {})
517 452

  
518 453
        # Permet de vérifier si l'utilisateur a bien les permissions
519 454
        # pour accéder à cet événement et si l'événement existe.
......
528 463
        # Pas d'événement ou permission refusée. On ne distingue pas
529 464
        # les 2 cas afin d'éviter la divulgation d'informations.
530 465
        if not events.num_rows():
531
            raise HTTPNotFound()
466
            raise HTTPNotFound(_('No such incident or insufficient permissions'))
532 467

  
533
        plugin = [i for i in plugins if i[0] == plugin_name][0]
468
        plugin_class = [p[1] for p in plugins if p[0] == plugin_name]
469
        if not plugin_class:
470
            raise HTTPNotFound(_('No such plugin'))
471

  
472
        plugin_class = plugin_class[0]
534 473
        try:
535 474
            mypac = __import__(
536
                'vigiboard.controllers.vigiboard_plugin.' + plugin[0],
537
                globals(), locals(), [plugin[1]], -1)
538
            plug = getattr(mypac, plugin[1])()
539
            return plug.controller(idcorrevent, *arg, **krgv)
475
                'vigiboard.controllers.vigiboard_plugin.' + plugin_name,
476
                globals(), locals(), [plugin_class], -1)
477
            plugin = getattr(mypac, plugin_class)
478
            if callable(plugin):
479
                return plugin().get_value(idcorrevent, *arg, **krgv)
480
            raise HTTPInternalServerError(_('Not a valid plugin'))
540 481
        except ImportError:
541
            raise HTTPNotFound()
482
            raise HTTPInternalServerError(_('Plugin could not be loaded'))
542 483

  
543 484
    @validate(validators={
544 485
        "fontsize": validators.Regex(
......
590 531
            last_modification_timestamp = value_if_none
591 532
    return datetime.fromtimestamp(mktime(
592 533
        last_modification_timestamp.timetuple()))
534

  
535
def get_plugins_instances():
536
    plugins = config.get('vigiboard_plugins', [])
537
    plugins_instances = []
538
    for (plugin_name, plugin_class) in plugins:
539
        try:
540
            mypac = __import__(
541
                'vigiboard.controllers.vigiboard_plugin.' + plugin_name,
542
                globals(), locals(), [plugin_class], -1)
543
            plugin = getattr(mypac, plugin_class)
544
            if callable(plugin):
545
                plugins_instances.append((plugin_name, plugin()))
546
        except ImportError:
547
            pass
548
    return plugins_instances
549

  
vigiboard/controllers/vigiboard_plugin/__init__.py
14 14
    def __init__ (self, table = None, join = None, outerjoin = None,
15 15
            filters = None, groupby = None, orderby = None, name = '',
16 16
            style = None, object_name = ""):
17

  
18 17
        self.table = table
19 18
        self.join = join
20 19
        self.outerjoin = outerjoin
......
25 24
        self.style = style
26 25
        self.object_name = object_name
27 26

  
28
    def __show__ (self, aggregate):
29
        """
30
        Permet d'éviter toutes erreurs d'affichage.
31
        C'est la fonction appelée par le formateur d'événements.
32
        """
33

  
34
        show = self.show(aggregate)
35

  
36
        if show != None:
37
            try:
38
                return str(show)
39
            except:
40
                return _('Error')
41

  
42
    def show(self, aggregate):
43
        """
44
        Fonction qui affichera par défaut une chaîne de
45
        caractères vide dans la colonne attribuée au plugin.
46

  
47
        En général, les plugins devront redéfinir cette fonction
48
        pour afficher ce qu'ils souhaitent.
27
    def get_value(self, idcorrevent, *args, **kwargs):
49 28
        """
29
        Cette méthode est appelée depuis le template associé à ce plugin,
30
        mais également lorsque l'on demande la valeur du plugin grâce à la
31
        méthode get_plugin_value du L{RootController} de VigiBoard.
50 32

  
51
        return ''
33
        Cette méthode DEVRAIT être surchargée dans les classes dérivées.
52 34

  
53
    def context(self, context):
54
        """
55
        Fonction permettant d'ajouter un contexte dans la page d'événements,
56
        comme par exemple un fichier CSS ou une fonction Javascript.
35
        @param idcorrevent: Identifiant du L{CorrEvent} à interroger.
36
        @type idcorrevent: C{int}
37
        @return: Dictionnaire contenant un texte statique.
38
        @rtype: C{dict}
57 39
        """
58

  
59
        pass
60
 
61
    
62
    def controller(self):
63
        """
64
        Fonction permettant de rajouter un pseudo-contrôleur pour le plugin.
65
        Ceci permet par exemple d'exécuter des requêtes JSON.
66
        """
67

  
68 40
        pass
vigiboard/controllers/vigiboard_plugin/date.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginDate(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/history.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
import urllib
8

  
9
from tg.exceptions import HTTPNotFound
10
from tg import flash, request, config, redirect, url
11
from pylons.i18n import ugettext as _
12

  
13
from vigiboard.controllers.vigiboardrequest import VigiboardRequest
14
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
15
from vigilo.models.configure import DBSession
16
from vigilo.models import User, CorrEvent, Event, StateName
17

  
18
class PluginHistory(VigiboardRequestPlugin):
19
    def get_value(self, idcorrevent, *args, **kwargs):
20
        """
21
        Renvoie les éléments pour l'affichage de la fenêtre de dialogue
22
        contenant des liens internes et externes.
23
        Pour accéder à cette page, l'utilisateur doit être authentifié.
24

  
25
        @param id: identifiant de l'événement
26
        """
27

  
28
        # Obtention de données sur l'événement et sur son historique
29
        username = request.environ.get('repoze.who.identity'
30
                    ).get('repoze.who.userid')
31

  
32
        username = request.environ['repoze.who.identity']['repoze.who.userid']
33
        events = VigiboardRequest(User.by_user_name(username))
34
        events.add_table(
35
            Event,
36
            events.items.c.hostname,
37
            events.items.c.servicename,
38
        )
39
        events.add_join((CorrEvent, CorrEvent.idcause == Event.idevent))
40
        events.add_join((events.items, 
41
            Event.idsupitem == events.items.c.idsupitem))
42
        events.add_filter(CorrEvent.idcorrevent == idcorrevent)
43

  
44
        # Vérification que au moins un des identifiants existe et est éditable
45
        # TODO: on est dans du JSON, donc flash/redirect ne fonctionneront pas!
46
        if events.num_rows() != 1:
47
            flash(_('No access to this event'), 'error')
48
            redirect('/')
49

  
50
        event = events.req[0]
51
        eventdetails = {}
52
        for edname, edlink in \
53
                config['vigiboard_links.eventdetails'].iteritems():
54

  
55
            # Rappel:
56
            # event[0] = priorité de l'alerte corrélée.
57
            # event[1] = alerte brute.
58
            if event.servicename:
59
                service = urllib.quote(event.servicename)
60
            else:
61
                service = None
62
            eventdetails[edname] = edlink[1] % {
63
                'idcorrevent': idcorrevent,
64
                'host': urllib.quote(event.hostname),
65
                'service': service,
66
                'message': urllib.quote(event[0].message),
67
            }
68

  
69
        return dict(
70
                current_state = StateName.value_to_statename(
71
                                    event[0].current_state),
72
                initial_state = StateName.value_to_statename(
73
                                    event[0].initial_state),
74
                peak_state = StateName.value_to_statename(
75
                                    event[0].peak_state),
76
                idcorrevent = idcorrevent,
77
                host = event.hostname,
78
                service = event.servicename,
79
                eventdetails = eventdetails,
80
            )
81

  
82

  
vigiboard/controllers/vigiboard_plugin/hls.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4
Plugin SHN : High level service
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginHLS(VigiboardRequestPlugin):
16

  
17
    """
18
    Plugin permettant de rajouter le nombre de Service de Haut Niveau
19
    impactés à l'affichage et d'obtenir une liste détaillée de ces
20
    Services de Haut Niveau.
21
    """
22
    def get_value(self, idcorrevent):
23
        """Ajout de fonctionnalités au contrôleur"""
24
        supitem = self.get_correvent_supitem(idcorrevent)
25

  
26
        if not supitem:
27
            return []
28

  
29
        services = supitem.impacted_hls(
30
            HighLevelService.servicename
31
        ).distinct().order_by(
32
            HighLevelService.servicename.asc()
33
        ).all()
34

  
35
        return {'services': [service.servicename for service in services]}
36

  
37
    def get_correvent_supitem(self, idcorrevent):
38
        """
39
        Retourne le supitem ayant causé l'évènement 
40
        corrélé dont l'identifiant est passé en paramètre.
41
        """
42
        # On récupère l'item recherché dans la BDD
43
        supitem = DBSession.query(SupItem
44
            ).join(
45
                (Event, Event.idsupitem == SupItem.idsupitem),
46
                (CorrEvent, CorrEvent.idcause == Event.idevent),
47
            ).filter(CorrEvent.idcorrevent == idcorrevent).first()
48
        return supitem
49

  
vigiboard/controllers/vigiboard_plugin/hostname.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginHostname(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/id.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginId(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/occurrences.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginOccurrences(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/output.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginOutput(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/priority.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginPriority(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/servicename.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginServicename(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/shn.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4
Plugin SHN : High level service
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginSHN(VigiboardRequestPlugin):
16

  
17
    """
18
    Plugin permettant de rajouter le nombre de SHNs impactés à
19
    l'affichage et d'obtenir une liste détaillée de ces SHNs.
20
    """
21

  
22
    def __init__(self):
23
        super(PluginSHN, self).__init__(
24
            name = _(u'Impacted HLS'),
25
            style = {'title': _(u'Impacted High-Level Services'),
26
                'style': 'text-align:center'},
27
            object_name = "shn"
28
        )
29
    
30
    def show(self, aggregate):
31
        """Fonction d'affichage"""
32
        supitem = DBSession.query(SupItem).join(
33
            (Event, Event.idsupitem == SupItem.idsupitem),
34
            (CorrEvent, CorrEvent.idcause == Event.idevent),
35
        ).filter(CorrEvent.idcorrevent == aggregate.idcorrevent).first()
36

  
37
        if not supitem:
38
            hls = None
39
        else:
40
            hls = supitem.impacted_hls(
41
                HighLevelService.servicename
42
            ).distinct().all()
43

  
44
        # Si aucun HLS n'est impacté, on n'affiche rien.
45
        if not hls:
46
            return ''
47

  
48
        # S'il n'y a qu'un seul HLS impacté,
49
        # on affiche directement son nom.
50
        if len(hls) == 1:
51
            return hls[0].servicename
52

  
53
        # Sinon, on affiche un lien permettant de récupérer
54
        # la liste de tous les HLS impactés. Le texte du lien
55
        # contient le nombre de HLS impactés.
56
        dico = {
57
            'baseurl': url('/'),
58
            'idcorrevent': aggregate.idcorrevent,
59
            'count': len(hls),
60
        }
61

  
62
        # XXX Il faudrait échapper l'URL contenue dans baseurl
63
        # pour éviter des attaques de type XSS.
64
        res = ('<a href="javascript:vigiboard_hls_dialog(this,' + \
65
                '\'%(baseurl)s\',%(idcorrevent)d)" ' + \
66
                'class="hls_link">%(count)d</a>') % dico
67
        return res
68

  
69
    def context(self, context):
70
        """Fonction de context"""
71
        context.append([None, self.object_name])
72

  
73
    def controller(self, idcorrevent, *argv, **krgv):
74
        """Ajout de fonctionnalités au contrôleur"""
75
        supitem = self.get_correvent_supitem(idcorrevent)
76

  
77
        if not supitem:
78
            return []
79

  
80
        services = supitem.impacted_hls(
81
            HighLevelService.servicename
82
        ).distinct().order_by(
83
            HighLevelService.servicename.asc()
84
        ).all()
85

  
86
        return dict(services=[service.servicename for service in services])
87

  
88
    def get_correvent_supitem(self, idcorrevent):
89
        """
90
        Retourne le supitem ayant causé l'évènement 
91
        corrélé dont l'identifiant est passé en paramètre.
92
        """
93
        # On récupère l'item recherché dans la BDD
94
        supitem = DBSession.query(SupItem
95
            ).join(
96
                (Event, Event.idsupitem == SupItem.idsupitem),
97
                (CorrEvent, CorrEvent.idcause == Event.idevent),
98
            ).filter(CorrEvent.idcorrevent == idcorrevent).first()
99
        return supitem
100

  
vigiboard/controllers/vigiboard_plugin/status.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginStatus(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboard_plugin/test.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4
Ce fichier contient un exemple de plugin pour l'interface
5
de VigiBoard. Il s'accompagne d'un template contenu dans
6
les thèmes, dans le répertoire suivant :
7
vigilo/themes/templates/vigiboard/vigiboard_plugin/test.html
8
"""
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11

  
12
class PluginTest(VigiboardRequestPlugin):
13
    """
14
    Un plugin de démonstration qui se contente d'afficher
15
    "Hello world" pour chaque événement du tableau.
16
    """
17

  
18
    def get_value(self, idcorrevent, *args, **kwargs):
19
        """
20
        Cette méthode est appelée depuis le template associé à ce plugin,
21
        mais également lorsque l'on demande la valeur du plugin grâce à la
22
        méthode get_plugin_value du L{RootController} de VigiBoard.
23

  
24
        @param idcorrevent: Identifiant du L{CorrEvent} à interroger.
25
        @type idcorrevent: C{int}
26
        @return: Dictionnaire contenant un texte statique.
27
        @rtype: C{dict}
28
        """
29
        return {'text': 'Hello world'}
30

  
vigiboard/controllers/vigiboard_plugin/tests.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4
Plugin for tests
5
"""
6

  
7
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
8
from vigilo.models import EventHistory, Event
9

  
10
class MonPlugin(VigiboardRequestPlugin):
11
    """Plugin de test"""
12
    
13
    def __init__(self):
14
        VigiboardRequestPlugin.__init__(
15
            self,
16
            table=[EventHistory.idevent],
17
            join=[(EventHistory, EventHistory.idevent == Event.idevent)],
18
            groupby=[EventHistory.idevent],
19
        )
20

  
21
    def show(self, aggregate):
22
        """Fonction d'affichage"""
23
        return aggregate
24

  
vigiboard/controllers/vigiboard_plugin/tt.py
1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""
4

  
5
"""
6

  
7
from pylons.i18n import ugettext as _
8
from tg import url
9

  
10
from vigiboard.controllers.vigiboard_plugin import VigiboardRequestPlugin
11
from vigilo.models.configure import DBSession
12
from vigilo.models import HighLevelService, \
13
                            CorrEvent, Event, SupItem
14

  
15
class PluginTroubleTicket(VigiboardRequestPlugin):
16
    pass
17

  
vigiboard/controllers/vigiboardrequest.py
138 138

  
139 139
        self.plugin = []
140 140
        self.events = []
141
        self.idevents = []
142
        self.hist = []
143 141
        self.req = DBSession
144 142
        self.context_fct = []
145 143

  
......
356 354
        self.generate_request()
357 355

  
358 356
        # Liste des éléments pour la tête du tableau
357
        self.events = []
359 358

  
360
        lst_title = [
361
                ['', {'class': 'small_col'}],
362
                [_('Date')+ '<span style="font-weight:normal">' + \
363
                        '<br />['+_('Duration') + ']</span>',
364
                        {'style':'text-align:left'}],
365
                [_('Priority'), {'title':_('ITIL Priority')}],
366
                ['#', {'title':_('Occurrence count')}],
367
                [_('Host'), {'style':'text-align:left'}],
368
                [_('Service Type')+'<br />'+_('Service Name'),
369
                    {'style':'text-align:left'}], 
370
                [_('Output'), {'style':'text-align:left'}]
371
                ]
372
        lst_title.extend([[plug.name, plug.style] for plug in self.plugin])
373
        lst_title.extend([['[' + _('TT') + ']', {'title': _('Trouble Ticket')}],
374
                            ['', {}]])
375
        events = [lst_title]
376
        i = 0
377
        class_tr = ['odd', 'even']
378
        ids = []
379
        for req in self.req[first_row : last_row]:
380
            # Si il y a plus d'un élément dans la liste des tables,
381
            # req devient une liste plutôt que d'être directement la
382
            # table souhaitée
383

  
384
            if isinstance(req, CorrEvent):
385
                event = req
386
            else:
387
                event = req[0]
388
                hostname = req.hostname
389
                servicename = req.servicename
390
            ids.append(event.idcause)
391

  
392
            # La liste pour l'événement actuel comporte dans l'ordre :
393
            #   L'événement en lui-même
394
            #   La classe à appliquer sur la ligne (permet d'alterner les
395
            #       couleurs suivant les lignes)
396
            #   La classe pour la case comportant la flèche de détails
397
            #   La classe pour la date, l'occurence et l'édition
398
            #   L'image à afficher pour la flèche de détails
399
            #   Une liste (une case par plugin) de ce que le plugin souhaite
400
            #       afficher en fonction de l'événement
401

  
402
            cause = event.cause
403

  
404
            events.append([
405
                    event,
406
                    hostname,
407
                    servicename,
408
                    {'class': class_tr[i % 2]},
409
                    {'class': StateName.value_to_statename(
410
                        cause.initial_state) +
411
                        self.class_ack[event.status]},
412
                    {'class': StateName.value_to_statename(
413
                        cause.current_state) +
414
                        self.class_ack[event.status]},
415
                    {'src': '/images/%s2.png' %
416
                        StateName.value_to_statename(
417
                        cause.current_state)},
418
                    self.format_events_status(event),
419
                    [[j.__show__(event), j.style] for j in self.plugin]
420
                ])
421
            i += 1
422

  
423
        # On sauvegarde la liste précédemment créée puis on remplit
424
        # le TmplContext
425
        self.events = events
426
        self.idevents = ids
359
        for data in self.req[first_row : last_row]:
360
            self.events.append((data[0], data.hostname, data.servicename))
427 361

  
428 362
    def format_history(self):
429 363
        """
......
433 367
        de l'affichage pour un historique donné.
434 368
        """
435 369

  
370
        ids = [data[0].idcause for data in self.events]
436 371
        history = DBSession.query(
437 372
                    EventHistory,
438
                ).filter(EventHistory.idevent.in_(self.idevents)
373
                ).filter(EventHistory.idevent.in_(ids)
439 374
                ).order_by(desc(EventHistory.timestamp)
440 375
                ).order_by(desc(EventHistory.idhistory))
441
        if history.count() == 0:
442
            self.hist = {}
443
            for i in self.idevents:
444
                self.hist[i] = []
445
            return
446 376

  
447 377
        hists = {}
448
        i = 0
449
        class_tr = ['odd', 'even']
450

  
451
        for hist in history:
452
            if not hist.idevent in hists:
453
                hists[hist.idevent] = []
454

  
455
            # La liste pour l'historique actuel comporte dans l'ordre :
456
            #   Le moment où il a été généré
457
            #   Qui l'a généré
458
            #   Le type d'action qui a été appliqué
459
            #   La valeur de l'action
460
            #   Le détail de l'action
461
            #   La classe à appliquer à la ligne
462
            #       (permet d'alterner les couleurs)
463

  
464
            hists[hist.idevent].append([
465
                hist.timestamp,
466
                hist.username,
467
                hist.type_action,
468
                hist.value,
469
                hist.text,
470
                {'class': class_tr[i % 2]},
471
            ])
472
            i += 1
473
        
474
        self.hist = hists
378
        for idevent in ids:
379
            hists[idevent] = []
380

  
381
        for entry in history:
382
            hists[entry.idevent].append(entry)
383

  
384
        return hists
475 385

  
476 386
    def generate_tmpl_context(self):
477 387
        """
......
482 392
        from vigiboard.controllers.root import get_last_modification_timestamp
483 393
        
484 394
        # Dialogue d'édition
395
        ids = [data[0].idcause for data in self.events]
485 396
        tmpl_context.edit_event_form = EditEventForm('edit_event_form',
486 397
            last_modification=mktime(get_last_modification_timestamp(
487
                self.idevents).timetuple()),
398
                ids).timetuple()),
488 399
            action=url('/update'), 
489 400
        )
490 401

  
......
492 403
        tmpl_context.search_form = SearchForm('search_form', lang=self.lang,
493 404
                                        # TRANSLATORS: Format de date et heure.
494 405
                                        date_format=_('%Y-%m-%d %I:%M:%S %p'))
495
        
496
        # Dialogue de détail d'un événement
497

  
498
        # Exécution des contexts des plugins
499
        for j in self.plugin:
500
            j.context(self.context_fct)
501 406

  
vigiboard/tests/functional/test_history_form.py
95 95
        DBSession.flush()
96 96
        transaction.commit()
97 97

  
98
        response = self.app.post('/history_dialog',
99
            {'idcorrevent': idcorrevent},
100
            extra_environ={'REMOTE_USER': 'manager'})
98
        response = self.app.post('/get_plugin_value', {
99
                'idcorrevent': idcorrevent,
100
                'plugin_name': 'history',
101
            }, extra_environ={'REMOTE_USER': 'manager'})
101 102
        json = response.json
102 103

  
103 104
        # Le contenu de "eventdetails" varie facilement.
......
122 123
        DBSession.flush()
123 124
        transaction.commit()
124 125

  
125
        response = self.app.post('/history_dialog',
126
            {'idcorrevent': idcorrevent},
127
            extra_environ={'REMOTE_USER': 'manager'})
126
        response = self.app.post('/get_plugin_value', {
127
                'idcorrevent': idcorrevent,
128
                'plugin_name': 'history',
129
            }, extra_environ={'REMOTE_USER': 'manager'})
128 130
        json = response.json
129 131

  
130 132
        # Le contenu de "eventdetails" varie facilement.
......
148 150
        DBSession.flush()
149 151
        transaction.commit()
150 152

  
151
        self.app.post('/history_dialog',
152
            {'idcorrevent': idcorrevent},
153
            extra_environ={'REMOTE_USER': 'manager'},
153
        self.app.post('/get_plugin_value', {
154
                'idcorrevent': idcorrevent,
155
                'plugin_name': 'history',
156
            }, extra_environ={'REMOTE_USER': 'manager'},
154 157
            status=302)
155 158

  
156 159
    def test_history_form_host_when_forbidden(self):
157
        """Teste le formulaire d'historique avec un LLS (alerte invisible)."""
160
        """Teste le formulaire d'historique avec un hôte (alerte invisible)."""
158 161
        idcorrevent = insert_deps(False)[1]
159 162
        DBSession.flush()
160 163
        transaction.commit()
161 164

  
162
        self.app.post('/history_dialog',
163
            {'idcorrevent': idcorrevent},
164
            extra_environ={'REMOTE_USER': 'manager'},
165
        self.app.post('/get_plugin_value', {
166
                'idcorrevent': idcorrevent,
167
                'plugin_name': 'history',
168
            }, extra_environ={'REMOTE_USER': 'manager'},
165 169
            status=302)
166 170

  
vigiboard/tests/functional/test_history_tables.py
103 103
    Test des historiques de Vigiboard.
104 104
    """
105 105

  
106
    def setUp(self):
107
        super(TestEventTable, self).setUp()
108
#        tg.config['vigiboard_plugins'] = [('history', 'PluginHistory')]
109

  
106 110
    def test_host_event_history(self):
107 111
        """Affichage de l'historique d'un évènement corrélé pour un hôte."""
108 112

  
vigiboard/tests/functional/test_host_vigiboardrequest.py
116 116
        tg.request = response.request
117 117

  
118 118
        # Derrière, VigiboardRequest doit charger le plugin de tests tout seul
119
        tg.config['vigiboard_plugins'] = [['tests', 'MonPlugin']]
119
#        tg.config['vigiboard_plugins'] = [['test', 'MonPlugin']]
120 120
        vigi_req = VigiboardRequest(User.by_user_name(u'editor'))
121 121
        vigi_req.add_table(
122 122
            CorrEvent,
......
137 137
        vigi_req.format_events(0, 10)
138 138
        vigi_req.format_history()
139 139
        assert_true(len(vigi_req.events) == 1 + 1,
140
            msg = "One history should be available for the user " +
140
            msg = "One history should be available for user " +
141 141
            "'editor' but there are %d" % (len(vigi_req.events) - 1))
142
        
143
#        # On s'assure que le plugin fonctionne correctement
144
#        assert_true(vigi_req.events[1][6][0][0] != 'Error', 
145
#                    msg = "Probleme d'execution des plugins ou de " +
146
#                        "formatage des evenements") 
147 142

  
148 143

  
149 144
        # On recommence les tests précédents avec l'utilisateur
......
173 168
        vigi_req.format_events(0, 10)
174 169
        vigi_req.format_history()
175 170
        assert_true(len(vigi_req.events) == 2 + 1,
176
            msg = "2 histories should be available for the user " +
171
            msg = "2 histories should be available for user " +
177 172
            "'manager' but there are %d" % (len(vigi_req.events) - 1))
178
        
179
        # On s'assure que le plugin fonctionne correctement
180
#        assert_true(vigi_req.events[1][6][0][0] != 'Error', 
181
#                    msg = "Probleme d'execution des plugins ou de " +
182
#                        "formatage des evenements") 
183 173

  
vigiboard/tests/functional/test_vigiboardrequest.py
186 186
        tg.request = response.request
187 187

  
188 188
        # Derrière, VigiboardRequest doit charger le plugin de tests tout seul
189
        tg.config['vigiboard_plugins'] = [['tests', 'MonPlugin']]
189
#        tg.config['vigiboard_plugins'] = [['tests', 'MonPlugin']]
190 190
        vigi_req = VigiboardRequest(User.by_user_name(u'editor'))
191 191
        vigi_req.add_table(
192 192
            CorrEvent,
......
210 210
        vigi_req.format_events(0, 10)
211 211
        vigi_req.format_history()
212 212
        assert_true(len(vigi_req.events) == 1 + 1,
213
            msg = "One history should be available for the user " +
213
            msg = "One history should be available for user " +
214 214
            "'editor' but there are %d" % (len(vigi_req.events) - 1))
215
#        assert_true(vigi_req.events[1][6][0][0] != 'Error', 
216
#                    msg = "Plugins execution or events formatting problem") 
217 215

  
218 216
        # On recommence les tests précédents avec l'utilisateur
219 217
        # manager (plus de droits)
......
240 238
        vigi_req.format_events(0, 10)
241 239
        vigi_req.format_history()
242 240
        assert_true(len(vigi_req.events) == 2 + 1, 
243
            msg = "2 histories should be available for the user " +
241
            msg = "2 histories should be available for user " +
244 242
            "'manager' but there are %d" % (len(vigi_req.events) - 1))
245
#        assert_true(vigi_req.events[1][6][0][0] != 'Error', 
246
#                    msg = "Plugins execution or events formatting problem") 
247 243

  
vigiboard/tests/functional/vigiboard_plugin/test_plugin_hls.py
116 116
    
117 117
    def test_no_impacted_hls(self):
118 118
        """
119
        Retour du plugin SHN pour 0 SHN impacté
119
        Retour du plugin HLS pour 0 HLS impacté
120 120
        Teste la valeur de retour du plugin lorsque
121 121
        aucun service de haut niveau n'est impacté.
122 122
        """
......
128 128
        DBSession.add(aggregate)
129 129
        
130 130
        ### 1er cas : l'utilisateur n'est pas connecté.
131
        # On vérifie que le plugin retourne bien une erreur 404.
131
        # On vérifie que le plugin retourne bien une erreur 401.
132 132
        resp = self.app.post(
133 133
            '/get_plugin_value', 
134 134
            {"idcorrevent" : str(aggregate.idcorrevent),
135
             "plugin_name" : "shn"},
135
             "plugin_name" : "hls"},
136 136
            status = 401,)
137 137
        
138 138
        ### 2ème cas : l'utilisateur n'a pas les
......
141 141
        resp = self.app.post(
142 142
            '/get_plugin_value', 
143 143
            {"idcorrevent" : str(aggregate.idcorrevent),
144
             "plugin_name" : "shn"},
144
             "plugin_name" : "hls"},
145 145
            status = 404,
146 146
            extra_environ={'REMOTE_USER': 'editor'})
147 147
        
148
        ### 3ème cas : l'utilisateur a cette fois les droits.        
148
        ### 3ème cas : l'utilisateur a cette fois les droits.
149 149
        resp = self.app.post(
150 150
            '/get_plugin_value', 
151 151
            {"idcorrevent" : str(aggregate.idcorrevent),
152
             "plugin_name" : "shn"},
152
             "plugin_name" : "hls"},
153 153
            extra_environ={'REMOTE_USER': 'manager'})
154 154
        # On vérifie que le plugin ne retourne toujours rien.
155 155
        assert_equal(resp.json, {"services": []})
156 156
    
157 157
    def test_1_impacted_hls_path(self):
158 158
        """
159
        Retour du plugin SHN pour 1 chemin impacté
159
        Retour du plugin HLS pour 1 chemin impacté
160 160
        Teste la valeur de retour du plugin lorsqu'un
161 161
        chemin de services de haut niveau est impacté.
162 162
        """
......
168 168
        DBSession.add(aggregate)
169 169
        
170 170
        ### 1er cas : l'utilisateur n'est pas connecté.
171
        # On vérifie que le plugin retourne bien une erreur 404.
171
        # On vérifie que le plugin retourne bien une erreur 401.
172 172
        resp = self.app.post(
173 173
            '/get_plugin_value', 
174 174
            {"idcorrevent" : str(aggregate.idcorrevent),
175
             "plugin_name" : "shn"},
175
             "plugin_name" : "hls"},
176 176
            status = 401,)
177 177
        
178
        ### 2ème cas : l'utilisateur n'a pas les
179
        ### droits sur l'hôte ayant causé le correvent.
178
        ### 2ème cas : l'utilisateur n'a pas les droits
179
        ### sur l'hôte ayant causé le correvent, on doit
180
        ### obtenir une erreur 404 (pas d'événement trouvé
181
        ### avec les informations liées à cet utilisateur).
180 182
        resp = self.app.post(
181 183
            '/get_plugin_value', 
182 184
            {"idcorrevent" : str(aggregate.idcorrevent),
183
             "plugin_name" : "shn"},
185
             "plugin_name" : "hls"},
184 186
            status = 404,
185 187
            extra_environ={'REMOTE_USER': 'editor'})
186 188
        
187
        ### 3ème cas : l'utilisateur a cette fois les droits.        
189
        ### 3ème cas : l'utilisateur a cette fois les droits.
188 190
        resp = self.app.post(
189 191
            '/get_plugin_value', 
190 192
            {"idcorrevent" : str(aggregate.idcorrevent),
191
             "plugin_name" : "shn"},
193
             "plugin_name" : "hls"},
192 194
            extra_environ={'REMOTE_USER': 'manager'})
193
        # On vérifie que le plugin retourne bien les 2 SHN impactés..
195
        # On vérifie que le plugin retourne bien les 2 HLS impactés.
194 196
        assert_equal(resp.json, {"services": ['HLS12']})
195 197
    
196 198
    def test_2_impacted_hls_path(self):
197 199
        """
198
        Retour du plugin SHN pour 2 chemins impactés
200
        Retour du plugin HLS pour 2 chemins impactés
199 201
        Teste la valeur de retour du plugin lorsque deux
200 202
        chemins de services de haut niveau sont impactés.
201 203
        """
......
207 209
        DBSession.add(aggregate)
208 210
        
209 211
        ### 1er cas : l'utilisateur n'est pas connecté.
210
        # On vérifie que le plugin retourne bien une erreur 404.
212
        # On vérifie que le plugin retourne bien une erreur 401.
211 213
        resp = self.app.post(
212 214
            '/get_plugin_value', 
213 215
            {"idcorrevent" : str(aggregate.idcorrevent),
214
             "plugin_name" : "shn"},
216
             "plugin_name" : "hls"},
215 217
            status = 401,)
216 218
        
217 219
        ### 2ème cas : l'utilisateur n'a pas les
......
219 221
        resp = self.app.post(
220 222
            '/get_plugin_value', 
221 223
            {"idcorrevent" : str(aggregate.idcorrevent),
222
             "plugin_name" : "shn"},
224
             "plugin_name" : "hls"},
223 225
            status = 404,
224 226
            extra_environ={'REMOTE_USER': 'editor'})
225 227
        
226
        ### 3ème cas : l'utilisateur a cette fois les droits.        
228
        ### 3ème cas : l'utilisateur a cette fois les droits.
227 229
        resp = self.app.post(
228 230
            '/get_plugin_value', 
229 231
            {"idcorrevent" : str(aggregate.idcorrevent),
230
             "plugin_name" : "shn"},
232
             "plugin_name" : "hls"},
231 233
            extra_environ={'REMOTE_USER': 'manager'})
232
        # On vérifie que le plugin retourne bien les 4 SHN impactés..
234
        # On vérifie que le plugin retourne bien les 4 HLS impactés.
233 235
        assert_equal(resp.json, {"services": ['HLS12', 'HLS22']})
234 236
        

Also available in: Unified diff