Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

vigiboard / vigiboard / controllers / root.py @ 3e6ee4db

History | View | Annotate | Download (16 KB)

1
# -*- coding: utf-8 -*-
2
# vim:set expandtab tabstop=4 shiftwidth=4: 
3
"""Vigiboard Controller"""
4

    
5
from tg import expose, validate, require, flash, \
6
    tmpl_context, request, config, session, redirect, url
7
from tw.forms import validators
8
from pylons.i18n import ugettext as _
9
from pylons.controllers.util import abort
10
from sqlalchemy import not_, and_, asc
11
from datetime import datetime
12
import math
13

    
14
from vigiboard.model import DBSession
15
from vigiboard.model import Event, EventHistory, EventsAggregate, \
16
                            Host, HostGroup, \
17
                            State, StateName, User
18
from repoze.what.predicates import Any, not_anonymous
19
from vigiboard.widgets.edit_event import edit_event_status_options
20
from vigiboard.controllers.vigiboardrequest import VigiboardRequest
21
from vigiboard.controllers.vigiboard_controller import VigiboardRootController
22

    
23
__all__ = ('RootController', )
24

    
25
class RootController(VigiboardRootController):
26
    
27
    """
28
    Le controller général de vigiboard
29
    """
30

    
31
    def process_form_errors(self, *argv, **kwargv):
32
        """
33
        Gestion des erreurs de validation : On affiche les erreurs
34
        puis on redirige vers la dernière page accédée.
35
        """
36
        for k in tmpl_context.form_errors:
37
            flash("'%s': %s" % (k, tmpl_context.form_errors[k]), 'error')
38
        if request.environ.get('HTTP_REFERER') :
39
            redirect(request.environ.get('HTTP_REFERER'
40
                ).split(request.environ.get('HTTP_HOST'))[1])
41
        else :
42
            redirect('/')
43

    
44
    @expose('vigiboard.html')
45
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
46
    def default(self, page = None, host = None, service = None, output = None,
47
            trouble_ticket=None, *argv, **krgv):
48
            
49
        """
50
        Page d'accueil de Vigiboard. Elle affiche, suivant la page demandée
51
        (page 1 par defaut), la liste des événements, rangés par ordre de prise
52
        en compte, puis de sévérité.
53
        Pour accéder à cette page, l'utilisateur doit être authentifié.
54

55
        @param page: Numéro de la page souhaitée, commence à 1
56
        @param host: Si l'utilisateur souhaite sélectionner seulement certains
57
                     événements suivant leur hôte, il peut placer une expression
58
                     ici en suivant la structure du LIKE en SQL
59
        @param service: Idem que host mais sur les services
60
        @param output: Idem que host mais sur le text explicatif
61
        @param trouble_ticket: Idem que host mais sur les tickets attribués
62
        """
63
        if page is None:
64
            page = 1
65

    
66
        try:
67
            page = int(page)
68
        except ValueError:
69
            abort(404)
70

    
71
        if page < 1:
72
            page = 1
73

    
74
        username = request.environ['repoze.who.identity']['repoze.who.userid']
75
        user = User.by_user_name(username)
76
        aggregates = VigiboardRequest(user)
77
        
78
        search = {
79
            'host': '',
80
            'service': '',
81
            'output': '',
82
            'tt': ''
83
        }
84
        # Application des filtres si nécessaire
85
        if host :
86
            search['host'] = host
87
            host = host.replace('%', '\\%').replace('_', '\\_') \
88
                    .replace('*', '%').replace('?', '_')
89
            aggregates.add_filter(Event.hostname.ilike('%%%s%%' % host))
90

    
91
        if service :
92
            search['service'] = service
93
            service = service.replace('%', '\\%').replace('_', '\\_') \
94
                    .replace('*', '%').replace('?', '_')
95
            aggregates.add_filter(Event.servicename.ilike('%%%s%%' % service))
96

    
97
        if output :
98
            search['output'] = output
99
            output = output.replace('%', '\\%').replace('_', '\\_') \
100
                    .replace('*', '%').replace('?', '_')
101
            aggregates.add_filter(Event.message.ilike('%%%s%%' % output))
102

    
103
        if trouble_ticket :
104
            search['tt'] = trouble_ticket
105
            trouble_ticket = trouble_ticket.replace('%', '\\%') \
106
                    .replace('_', '\\_').replace('*', '%').replace('?', '_')
107
            aggregates.add_filter(EventsAggregate.trouble_ticket.ilike(
108
                '%%%s%%' % trouble_ticket))
109

    
110
        # Calcul des éléments à afficher et du nombre de pages possibles
111
        total_rows = aggregates.num_rows()
112
        items_per_page = int(config['vigiboard_items_per_page'])
113

    
114
        if total_rows <= items_per_page * (page-1):
115
            page = 1
116
        id_first_row = items_per_page * (page-1)
117
        id_last_row = min(id_first_row + items_per_page, total_rows)
118

    
119
        aggregates.format_events(id_first_row, id_last_row)
120
        aggregates.generate_tmpl_context()
121
        nb_pages = int(math.ceil(total_rows / (items_per_page + 0.0)))
122

    
123
        return dict(
124
               events = aggregates.events,
125
               rows_info = {
126
                   'id_first_row': id_first_row + 1,
127
                   'id_last_row': id_last_row,
128
                   'total_rows': total_rows,
129
               },
130
               pages = range(1, nb_pages + 1),
131
               page = page,
132
               event_edit_status_options = edit_event_status_options,
133
               history = [],
134
               hist_error = False,
135
               plugin_context = aggregates.context_fct,
136
               search = search,
137
            )
138
      
139
    @validate(validators={'idaggregate':validators.String(not_empty=True)},
140
            error_handler=process_form_errors)
141
    @expose('json')
142
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
143
    def history_dialog(self, idaggregate):
144
        
145
        """
146
        JSon renvoyant les éléments pour l'affichage de la fenêtre de dialogue
147
        contenant des liens internes et externes.
148
        Pour accéder à cette page, l'utilisateur doit être authentifié.
149

150
        @param id: identifiant de l'événement
151
        """
152

    
153
        # Obtention de données sur l'événement et sur son historique
154
        username = request.environ.get('repoze.who.identity'
155
                    ).get('repoze.who.userid')
156
        user = User.by_user_name(username)
157

    
158
        event = DBSession.query(
159
                        EventsAggregate.priority,
160
                        Event,
161
                 ).join(
162
                    (Event, EventsAggregate.idcause == Event.idevent),
163
                    (HostGroup, Event.hostname == HostGroup.hostname),
164
                 ).filter(HostGroup.idgroup.in_(user.groups)
165
                 ).filter(EventsAggregate.idaggregate == idaggregate
166
                 ).one()
167

    
168
        history = DBSession.query(
169
                    EventHistory,
170
                 ).filter(EventHistory.idevent == event[1].idevent
171
                 ).order_by(asc(EventHistory.timestamp)
172
                 ).order_by(asc(EventHistory.type_action)).all()
173

    
174
        eventdetails = {}
175
        for edname, edlink in \
176
                config['vigiboard_links.eventdetails'].iteritems():
177

    
178
            eventdetails[edname] = edlink[1] % {
179
                    'idaggregate': idaggregate,
180
                    'host': event[1].hostname,
181
                    'service': event[1].servicename
182
                    }
183

    
184
        return dict(
185
                current_state = StateName.value_to_statename(
186
                                    event[1].current_state),
187
                initial_state = StateName.value_to_statename(
188
                                    event[1].initial_state),
189
                peak_state = StateName.value_to_statename(
190
                                    event[1].peak_state),
191
                idaggregate = idaggregate,
192
                host = event[1].hostname,
193
                service = event[1].servicename,
194
                eventdetails = eventdetails,
195
            )
196

    
197
    @validate(validators={'idaggregate':validators.String(not_empty=True)},
198
            error_handler=process_form_errors)
199
    @expose('vigiboard.html')
200
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
201
    def event(self, idaggregate):
202
        """
203
        Affichage de l'historique d'un événement.
204
        Pour accéder à cette page, l'utilisateur doit être authentifié.
205

206
        @param idevent: identifiant de l'événement souhaité
207
        """
208

    
209
        username = request.environ['repoze.who.identity']['repoze.who.userid']
210
        events = VigiboardRequest(User.by_user_name(username))
211
        events.add_filter(EventsAggregate.idaggregate == idaggregate)
212
        
213
        # Vérification que l'événement existe
214
        if events.num_rows() != 1 :
215
            flash(_('Error in DB'), 'error')
216
            redirect('/')
217
       
218
        events.format_events(0, 1)
219
        events.format_history()
220
        events.generate_tmpl_context() 
221

    
222
        return dict(
223
                    events = events.events,
224
                    rows_info = {
225
                        'id_first_row': 1,
226
                        'id_last_row': 1,
227
                        'total_rows': 1,
228
                    },
229
                    pages = [1],
230
                    page = 1,
231
                    event_edit_status_options = edit_event_status_options,
232
                    history = events.hist,
233
                    hist_error = True,
234
                    plugin_context = events.context_fct,
235
                    search = {
236
                        'host': None,
237
                        'service': None,
238
                        'output': None,
239
                        'tt': None
240
                    }
241
                )
242

    
243
    @validate(validators={'host':validators.NotEmpty(),
244
        'service':validators.NotEmpty()}, error_handler=process_form_errors)
245
    @expose('vigiboard.html')
246
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
247
    def host_service(self, host, service):
248
        
249
        """
250
        Affichage de l'historique de l'ensemble des événements correspondant
251
        au host et service demandé.
252
        Pour accéder à cette page, l'utilisateur doit être authentifié.
253

254
        @param host: Nom de l'hôte souhaité.
255
        @param service: Nom du service souhaité
256
        """
257

    
258
        username = request.environ['repoze.who.identity']['repoze.who.userid']
259
        events = VigiboardRequest(User.by_user_name(username))
260
        events.add_filter(Event.hostname == host,
261
                Event.servicename == service)
262
        # XXX On devrait avoir une autre API que ça !!!
263
        # Supprime le filtre qui empêche d'obtenir des événements fermés
264
        # (ie: ayant l'état Nagios 'OK' et le statut 'AAClosed').
265
        if len(events.filter) > 2:
266
            del events.filter[2]
267

    
268
        # Vérification qu'il y a au moins 1 événement qui correspond
269
        if events.num_rows() == 0 :
270
            redirect('/')
271

    
272
        events.format_events(0, events.num_rows())
273
        events.format_history()
274
        events.generate_tmpl_context()
275

    
276
        return dict(
277
                    events = events.events,
278
                    rows_info = {
279
                        'id_first_row': 1,
280
                        'id_last_row': 1,
281
                        'total_rows': 1,
282
                    },
283
                    pages = [1],
284
                    page = 1,
285
                    event_edit_status_options = edit_event_status_options,
286
                    history = events.hist,
287
                    hist_error = True,
288
                    plugin_context = events.context_fct,
289
                    search = {
290
                        'host': None,
291
                        'service': None,
292
                        'output': None,
293
                        'tt': None
294
                    }
295
                )
296

    
297
    @validate(validators={
298
        "id":validators.Regex(r'^[^,]+(,[^,]*)*,?$'),
299
#        "trouble_ticket":validators.Regex(r'^[0-9]*$'),
300
        "status":validators.OneOf(['NoChange', 'None', 'Acknowledged',
301
                'AAClosed'])
302
        }, error_handler=process_form_errors)
303
    @require(Any(not_anonymous(), msg=_("You need to be authenticated")))
304
    def update(self,**krgv):
305
        
306
        """
307
        Mise à jour d'un événement suivant les arguments passés.
308
        Cela peut être un changement de ticket ou un changement de statut.
309
        
310
        @param krgv['id']: Le ou les identifiants des événements à traiter
311
        @param krgv['tt']: Nouveau numéro du ticket associé.
312
        @param krgv['status']: Nouveau status de/des événements.
313
        """
314
        
315
        # Si l'utilisateur édite plusieurs événements à la fois,
316
        # il nous faut chacun des identifiants
317

    
318
        if krgv['id'] is None:
319
            flash(_('No event has been selected'), 'warning')
320
            raise redirect(request.environ.get('HTTP_REFERER', url('/')))
321

    
322
        ids = krgv['id'].split(',')
323
       
324
        if len(ids) > 1 :
325
            ids = ids[:-1]
326
        
327
        username = request.environ['repoze.who.identity']['repoze.who.userid']
328
        events = VigiboardRequest(User.by_user_name(username))
329
        events.add_filter(EventsAggregate.idaggregate.in_(ids))
330
        
331
        # Vérification que au moins un des identifiants existe et est éditable
332
        if events.num_rows() <= 0 :
333
            flash(_('No access to this event'), 'error')
334
            redirect('/')
335
        
336
        # Modification des événements et création d'un historique
337
        # pour chacun d'eux.
338
        username = request.environ['repoze.who.identity']['repoze.who.userid']
339

    
340
        for req in events.req:
341
            if isinstance(req, EventsAggregate):
342
                event = req
343
            else:
344
                event = req[0]
345

    
346
            if krgv['trouble_ticket'] != '' :
347
                history = EventHistory(
348
                        type_action="Ticket change",
349
                        idevent=event.idcause,
350
                        value=krgv['trouble_ticket'],
351
                        text=_("Changed trouble ticket from '%s' to '%s'") % (
352
                            event.trouble_ticket, krgv['trouble_ticket']
353
                        ),
354
                        username=username,
355
                        timestamp=datetime.now(),
356
                    )
357
                DBSession.add(history)   
358
                event.trouble_ticket = krgv['trouble_ticket']
359

    
360
            if krgv['status'] != 'NoChange' :
361
                history = EventHistory(
362
                        type_action="Acknowlegement change state",
363
                        idevent=event.idcause,
364
                        value=krgv['status'],
365
                        text=_("Changed acknowledgement status from '%s' to '%s'") % (
366
                            event.status, krgv['status']
367
                        ),
368
                        username=username,
369
                        timestamp=datetime.now(),
370
                    )
371
                DBSession.add(history)
372
                event.status = krgv['status']
373

    
374
        DBSession.flush()
375
        flash(_('Updated successfully'))
376
        redirect(request.environ.get('HTTP_REFERER', url('/')))
377

    
378

    
379
    @validate(validators={"plugin_name":validators.OneOf(
380
        [i for [i, j] in config.get('vigiboard_plugins', [])])},
381
                error_handler = process_form_errors)
382
    @expose('json')
383
    def get_plugin_value(self, plugin_name, *arg, **krgv):
384
        """
385
        Permet aux plugins de pouvoir récupérer des valeurs Json
386
        """
387
        plugins = config['vigiboard_plugins']
388
        if plugins is None:
389
            return
390

    
391
        plugin = [i for i in plugins if i[0] == plugin_name][0]
392
        try:
393
            mypac = __import__(
394
                'vigiboard.controllers.vigiboard_plugin.' + plugin[0],
395
                globals(), locals(), [plugin[1]], -1)
396
            plug = getattr(mypac, plugin[1])()
397
            return plug.controller(*arg, **krgv)
398
        except:
399
            raise
400
    
401
#    @validate(validators= {"fontsize": validators.Int()},
402
#                    error_handler = process_form_errors)
403
    @expose('json')
404
    def set_fontsize(self, fontsize):
405
        """
406
        Save font size
407
        """
408
        session['fontsize'] = fontsize
409
        session.save()
410
        return dict(ret= 'ok')
411

    
412
    @validate(validators= {"refresh": validators.Int()},
413
            error_handler = process_form_errors)
414
    @expose('json')
415
    def set_refresh(self, refresh):
416
        """
417
        Save refresh time
418
        """
419
        session['refresh'] = refresh
420
        session.save()
421
        return dict(ret= 'ok')
422