vigiboard / vigiboard / controllers / root.py @ c94dc931
History | View | Annotate | Download (39.4 KB)
1 | 19e88cb8 | Thomas ANDREJAK | # -*- coding: utf-8 -*-
|
---|---|---|---|
2 | e3c52cfd | Aurelien BOMPARD | # vim:set expandtab tabstop=4 shiftwidth=4:
|
3 | c94dc931 | Francois POIROTTE | # Copyright (C) 2007-2020 CS-SI
|
4 | 9b8d9497 | Francois POIROTTE | # License: GNU GPL v2 <http://www.gnu.org/licenses/gpl-2.0.html>
|
5 | a77de887 | Francois POIROTTE | |
6 | e181e86c | Francois POIROTTE | """VigiBoard Controller"""
|
7 | 19e88cb8 | Thomas ANDREJAK | |
8 | 1c5486c7 | Francois POIROTTE | import calendar |
9 | 02c4a1e7 | Francois POIROTTE | import gettext |
10 | import os.path |
||
11 | 7365fb51 | Francois POIROTTE | from datetime import datetime |
12 | |||
13 | 915f3245 | Francois POIROTTE | from pkg_resources import resource_filename, working_set |
14 | db6fbc92 | Aurelien BOMPARD | |
15 | 27140946 | Francois POIROTTE | from tg.exceptions import HTTPNotFound |
16 | 4b573169 | Francois POIROTTE | from tg import expose, validate, require, flash, url, \ |
17 | a2fa6a5b | Francois POIROTTE | tmpl_context, request, response, config, session, redirect |
18 | 02c4a1e7 | Francois POIROTTE | from tg.support import paginate |
19 | from formencode import validators, schema |
||
20 | from tg.i18n import ugettext as _, lazy_ugettext as l_, get_lang |
||
21 | 6ab72614 | Vincent QUEMENER | from sqlalchemy import asc |
22 | 97f6d842 | Vincent QUEMENER | from sqlalchemy.sql import func |
23 | eec46cb0 | Vincent QUEMENER | from sqlalchemy.orm import aliased |
24 | 6520dbc0 | Vincent QUEMENER | from sqlalchemy.sql.expression import or_ |
25 | 02c4a1e7 | Francois POIROTTE | from tg.predicates import Any, All, NotAuthorizedError, \ |
26 | has_permission, not_anonymous |
||
27 | ee3ae8c8 | Francois POIROTTE | |
28 | e7e3d45e | Francois POIROTTE | from vigilo.models.session import DBSession |
29 | a05b9a37 | Francois POIROTTE | from vigilo.models.tables import Event, EventHistory, CorrEvent, Host, \ |
30 | 9e0ea30e | Francois POIROTTE | SupItem, SupItemGroup, LowLevelService, \ |
31 | eec46cb0 | Vincent QUEMENER | StateName, State, DataPermission |
32 | 0bd9c069 | Francois POIROTTE | from vigilo.models.tables.grouphierarchy import GroupHierarchy |
33 | eec46cb0 | Vincent QUEMENER | from vigilo.models.tables.secondary_tables import EVENTSAGGREGATE_TABLE, \ |
34 | 6520dbc0 | Vincent QUEMENER | USER_GROUP_TABLE, SUPITEM_GROUP_TABLE |
35 | 7365fb51 | Francois POIROTTE | |
36 | ddbaec88 | Francois POIROTTE | from vigilo.turbogears.controllers.auth import AuthController |
37 | f1886725 | Vincent QUEMENER | from vigilo.turbogears.controllers.selfmonitoring import SelfMonitoringController |
38 | ff8eda22 | Francois POIROTTE | from vigilo.turbogears.controllers.custom import CustomController |
39 | ddbaec88 | Francois POIROTTE | from vigilo.turbogears.controllers.error import ErrorController |
40 | e307e626 | Francois POIROTTE | from vigilo.turbogears.controllers.autocomplete import AutoCompleteController |
41 | ea0e5dfb | Francois POIROTTE | from vigilo.turbogears.controllers.proxy import ProxyController |
42 | f6ecd27a | Francois POIROTTE | from vigilo.turbogears.controllers.i18n import I18nController |
43 | 98a40b9f | Aurelien BOMPARD | from vigilo.turbogears.controllers.api.root import ApiRootController |
44 | 195aa50d | Francois POIROTTE | from vigilo.turbogears.helpers import get_current_user |
45 | |||
46 | 7365fb51 | Francois POIROTTE | from vigiboard.controllers.vigiboardrequest import VigiboardRequest |
47 | bc31210c | Francois POIROTTE | from vigiboard.controllers.feeds import FeedsController |
48 | d5a41c9b | Vincent QUEMENER | from vigiboard.controllers.silence import SilenceController |
49 | 2dbc5942 | Francois POIROTTE | |
50 | 00ece25a | Francois POIROTTE | from vigiboard.lib import export_csv, dateformat |
51 | 4b573169 | Francois POIROTTE | from vigiboard.widgets.edit_event import edit_event_status_options, \ |
52 | EditEventForm
|
||
53 | 27140946 | Francois POIROTTE | from vigiboard.widgets.search_form import create_search_form |
54 | 7f26a756 | Francois POIROTTE | import logging |
55 | |||
56 | LOGGER = logging.getLogger(__name__) |
||
57 | 19e88cb8 | Thomas ANDREJAK | |
58 | e3c52cfd | Aurelien BOMPARD | __all__ = ('RootController', 'get_last_modification_timestamp', |
59 | 97f6d842 | Vincent QUEMENER | 'date_to_timestamp')
|
60 | 19e88cb8 | Thomas ANDREJAK | |
61 | 8b2edebe | Aurelien BOMPARD | # pylint: disable-msg=R0201,W0613,W0622
|
62 | # R0201: Method could be a function
|
||
63 | # W0613: Unused arguments: les arguments sont la query-string
|
||
64 | # W0622: Redefining built-in 'id': élément de la query-string
|
||
65 | |||
66 | f6ecd27a | Francois POIROTTE | class RootController(AuthController, SelfMonitoringController, I18nController): |
67 | 19e88cb8 | Thomas ANDREJAK | """
|
68 | Le controller général de vigiboard
|
||
69 | """
|
||
70 | 915f3245 | Francois POIROTTE | _tickets = None
|
71 | 02c4a1e7 | Francois POIROTTE | _use_index_fallback = True
|
72 | 915f3245 | Francois POIROTTE | |
73 | ddbaec88 | Francois POIROTTE | error = ErrorController() |
74 | e307e626 | Francois POIROTTE | autocomplete = AutoCompleteController() |
75 | ea0e5dfb | Francois POIROTTE | nagios = ProxyController('nagios', '/nagios/', |
76 | not_anonymous(l_('You need to be authenticated')))
|
||
77 | 17516734 | Francois Poirotte | api = ApiRootController() |
78 | bc31210c | Francois POIROTTE | feeds = FeedsController() |
79 | d5a41c9b | Vincent QUEMENER | silence = SilenceController() |
80 | ff8eda22 | Francois POIROTTE | custom = CustomController() |
81 | ef31cc13 | Francois POIROTTE | |
82 | f2e30877 | Francois POIROTTE | # Prédicat pour la restriction de l'accès aux interfaces.
|
83 | a5f99051 | Francois POIROTTE | # L'utilisateur doit avoir la permission "vigiboard-access"
|
84 | f2e30877 | Francois POIROTTE | # ou appartenir au groupe "managers" pour accéder à VigiBoard.
|
85 | access_restriction = All( |
||
86 | not_anonymous(msg=l_("You need to be authenticated")),
|
||
87 | 73119f8a | Francois POIROTTE | Any(config.is_manager, |
88 | a5f99051 | Francois POIROTTE | has_permission('vigiboard-access'),
|
89 | msg=l_("You don't have access to VigiBoard"))
|
||
90 | f2e30877 | Francois POIROTTE | ) |
91 | |||
92 | aa0788a2 | Francois POIROTTE | def process_form_errors(self, *argv, **kwargv): |
93 | 19e88cb8 | Thomas ANDREJAK | """
|
94 | 27140946 | Francois POIROTTE | Gestion des erreurs de validation : on affiche les erreurs
|
95 | 19e88cb8 | Thomas ANDREJAK | puis on redirige vers la dernière page accédée.
|
96 | """
|
||
97 | aa0788a2 | Francois POIROTTE | for k in tmpl_context.form_errors: |
98 | flash("'%s': %s" % (k, tmpl_context.form_errors[k]), 'error') |
||
99 | a9a4679d | Francois POIROTTE | redirect(request.environ.get('HTTP_REFERER', '/')) |
100 | 19e88cb8 | Thomas ANDREJAK | |
101 | 4c08cd96 | Francois POIROTTE | @expose('json') |
102 | def handle_validation_errors_json(self, *args, **kwargs): |
||
103 | kwargs['errors'] = tmpl_context.form_errors
|
||
104 | return dict(kwargs) |
||
105 | e3c52cfd | Aurelien BOMPARD | |
106 | 915f3245 | Francois POIROTTE | def __init__(self, *args, **kwargs): |
107 | """Initialisation du contrôleur."""
|
||
108 | super(RootController, self).__init__(*args, **kwargs) |
||
109 | # Si un module de gestion des tickets a été indiqué dans
|
||
110 | # le fichier de configuration, on tente de le charger.
|
||
111 | if config.get('tickets.plugin'): |
||
112 | plugins = working_set.iter_entry_points('vigiboard.tickets', config['tickets.plugin']) |
||
113 | if plugins:
|
||
114 | # La classe indiquée par la première valeur de l'itérateur
|
||
115 | # correspond au plugin que l'on veut instancier.
|
||
116 | pluginCls = plugins.next().load() |
||
117 | self._tickets = pluginCls()
|
||
118 | |||
119 | 0081c9f2 | Francois POIROTTE | class IndexSchema(schema.Schema): |
120 | """Schéma de validation de la méthode index."""
|
||
121 | 338575f6 | Francois POIROTTE | # Si on ne passe pas le paramètre "page" ou qu'on passe une valeur
|
122 | # invalide ou pas de valeur du tout, alors on affiche la 1ère page.
|
||
123 | 5a845c93 | Vincent QUEMENER | page = validators.Int( |
124 | min=1,
|
||
125 | if_missing=1,
|
||
126 | if_invalid=1,
|
||
127 | not_empty=True
|
||
128 | ) |
||
129 | |||
130 | # Paramètres de tri
|
||
131 | 02c4a1e7 | Francois POIROTTE | sort = validators.UnicodeString(if_missing='')
|
132 | 5a845c93 | Vincent QUEMENER | order = validators.OneOf(['asc', 'desc'], if_missing='asc') |
133 | 27140946 | Francois POIROTTE | |
134 | 02c4a1e7 | Francois POIROTTE | # Le fait de chaîner la validation avec le formulaire de recherche
|
135 | # permet de convertir les critères de recherche vers leur type.
|
||
136 | 27140946 | Francois POIROTTE | chained_validators = [create_search_form.validator] |
137 | e307e626 | Francois POIROTTE | |
138 | 02c4a1e7 | Francois POIROTTE | allow_extra_fields = True
|
139 | |||
140 | e307e626 | Francois POIROTTE | @validate(
|
141 | 0081c9f2 | Francois POIROTTE | validators=IndexSchema(), |
142 | e307e626 | Francois POIROTTE | error_handler = process_form_errors) |
143 | 02c4a1e7 | Francois POIROTTE | @expose('events_table.html') |
144 | f2e30877 | Francois POIROTTE | @require(access_restriction)
|
145 | 02c4a1e7 | Francois POIROTTE | def index(self, page=None, sort=None, order=None, **search): |
146 | 19e88cb8 | Thomas ANDREJAK | """
|
147 | bc94248f | Francois POIROTTE | Page d'accueil de Vigiboard. Elle affiche, suivant la page demandée
|
148 | a2a22ade | Francois POIROTTE | (page 1 par defaut), la liste des événements, rangés par ordre de prise
|
149 | bc94248f | Francois POIROTTE | en compte, puis de sévérité.
|
150 | 19e88cb8 | Thomas ANDREJAK | Pour accéder à cette page, l'utilisateur doit être authentifié.
|
151 |
|
||
152 | bc94248f | Francois POIROTTE | @param page: Numéro de la page souhaitée, commence à 1
|
153 | 27140946 | Francois POIROTTE | @type page: C{int}
|
154 | 5a845c93 | Vincent QUEMENER | @param sort: Colonne de tri
|
155 | @type sort: C{str} or C{None}
|
||
156 | @param order: Ordre du tri (asc ou desc)
|
||
157 | @type order: C{str} or C{None}
|
||
158 | 27140946 | Francois POIROTTE | @param search: Dictionnaire contenant les critères de recherche.
|
159 | @type search: C{dict}
|
||
160 | c9245ffc | Vincent QUEMENER |
|
161 | e3c52cfd | Aurelien BOMPARD | Cette méthode permet de satisfaire les exigences suivantes :
|
162 | - VIGILO_EXIG_VIGILO_BAC_0040,
|
||
163 | e181e86c | Francois POIROTTE | - VIGILO_EXIG_VIGILO_BAC_0070,
|
164 | - VIGILO_EXIG_VIGILO_BAC_0100,
|
||
165 | 19e88cb8 | Thomas ANDREJAK | """
|
166 | f1886725 | Vincent QUEMENER | |
167 | # Auto-supervision
|
||
168 | self.get_failures()
|
||
169 | |||
170 | 195aa50d | Francois POIROTTE | user = get_current_user() |
171 | 5a845c93 | Vincent QUEMENER | aggregates = VigiboardRequest(user, search=search, sort=sort, order=order) |
172 | cf3c2494 | Vincent QUEMENER | |
173 | 911069bc | Francois POIROTTE | aggregates.add_table( |
174 | CorrEvent, |
||
175 | b2668166 | Francois POIROTTE | aggregates.items.c.address, |
176 | 911069bc | Francois POIROTTE | aggregates.items.c.hostname, |
177 | aggregates.items.c.servicename |
||
178 | ) |
||
179 | aggregates.add_join((Event, CorrEvent.idcause == Event.idevent)) |
||
180 | cf3c2494 | Vincent QUEMENER | aggregates.add_contains_eager(CorrEvent.cause) |
181 | aggregates.add_group_by(Event) |
||
182 | e3c52cfd | Aurelien BOMPARD | aggregates.add_join((aggregates.items, |
183 | bfd8ead8 | Vincent QUEMENER | Event.idsupitem == aggregates.items.c.idsupitem)) |
184 | 5d20c2c5 | Francois POIROTTE | aggregates.add_order_by(asc(aggregates.items.c.hostname)) |
185 | e3c52cfd | Aurelien BOMPARD | |
186 | adb0e63f | Francois POIROTTE | # On ne garde que les champs effectivement renseignés.
|
187 | for column in search.copy(): |
||
188 | if not search[column]: |
||
189 | del search[column]
|
||
190 | |||
191 | # On sérialise les champs de type dict.
|
||
192 | def serialize_dict(dct, key): |
||
193 | if isinstance(dct[key], dict): |
||
194 | for subkey in dct[key]: |
||
195 | serialize_dict(dct[key], subkey) |
||
196 | 00ece25a | Francois POIROTTE | dct['%s.%s' % (key, subkey)] = dct[key][subkey]
|
197 | adb0e63f | Francois POIROTTE | del dct[key]
|
198 | 00ece25a | Francois POIROTTE | elif isinstance(dct[key], datetime): |
199 | dct[key] = dct[key].strftime(dateformat.get_date_format()) |
||
200 | adb0e63f | Francois POIROTTE | fixed_search = search.copy() |
201 | for column in fixed_search.copy(): |
||
202 | serialize_dict(fixed_search, column) |
||
203 | |||
204 | 4b573169 | Francois POIROTTE | # Pagination des résultats
|
205 | aggregates.generate_request() |
||
206 | 36f6910e | Francois POIROTTE | items_per_page = int(session.get('items_per_page', config['vigiboard_items_per_page'])) |
207 | 27140946 | Francois POIROTTE | page = paginate.Page(aggregates.req, page=page, |
208 | items_per_page=items_per_page) |
||
209 | 3d0d254c | Francois POIROTTE | |
210 | cf3c2494 | Vincent QUEMENER | # Récupération des données des plugins
|
211 | plugins_data = {} |
||
212 | plugins = dict(config['columns_plugins']) |
||
213 | 4b573169 | Francois POIROTTE | |
214 | ids_events = [event[0].idcause for event in page.items] |
||
215 | ids_correvents = [event[0].idcorrevent for event in page.items] |
||
216 | cf3c2494 | Vincent QUEMENER | for plugin in plugins: |
217 | 4b573169 | Francois POIROTTE | plugin_data = plugins[plugin].get_bulk_data(ids_correvents) |
218 | if plugin_data:
|
||
219 | cf3c2494 | Vincent QUEMENER | plugins_data[plugin] = plugin_data |
220 | a2fa6a5b | Francois POIROTTE | else:
|
221 | plugins_data[plugin] = {} |
||
222 | cf3c2494 | Vincent QUEMENER | |
223 | 4b573169 | Francois POIROTTE | # Ajout des formulaires et préparation
|
224 | # des données pour ces formulaires.
|
||
225 | 1c5486c7 | Francois POIROTTE | tmpl_context.last_modification = calendar.timegm( |
226 | get_last_modification_timestamp(ids_events).timetuple()) |
||
227 | 4b573169 | Francois POIROTTE | |
228 | tmpl_context.edit_event_form = EditEventForm("edit_event_form",
|
||
229 | submit_text=_('Apply'), action=url('/update')) |
||
230 | |||
231 | a2fa6a5b | Francois POIROTTE | if request.response_type == 'text/csv': |
232 | # Sans les 2 en-têtes suivants qui désactivent la mise en cache,
|
||
233 | # Internet Explorer refuse de télécharger le fichier CSV (cf. #961).
|
||
234 | response.headers['Pragma'] = 'public' # Nécessaire pour IE. |
||
235 | response.headers['Cache-Control'] = 'max-age=0' # Nécessaire pour IE. |
||
236 | |||
237 | 377a9c23 | Francois POIROTTE | response.headers["Content-Type"] = "text/csv" |
238 | a2fa6a5b | Francois POIROTTE | response.headers['Content-Disposition'] = \
|
239 | 'attachment;filename="alerts.csv"'
|
||
240 | return export_csv.export(page, plugins_data)
|
||
241 | |||
242 | 19e88cb8 | Thomas ANDREJAK | return dict( |
243 | 73f3220e | Vincent QUEMENER | hostname = None,
|
244 | servicename = None,
|
||
245 | cf3c2494 | Vincent QUEMENER | plugins_data = plugins_data, |
246 | 1101e03e | Francois POIROTTE | page = page, |
247 | 5a845c93 | Vincent QUEMENER | sort = sort, |
248 | order = order, |
||
249 | 1101e03e | Francois POIROTTE | event_edit_status_options = edit_event_status_options, |
250 | 2dbc5942 | Francois POIROTTE | search_form = create_search_form, |
251 | 1101e03e | Francois POIROTTE | search = search, |
252 | adb0e63f | Francois POIROTTE | fixed_search = fixed_search, |
253 | 1101e03e | Francois POIROTTE | ) |
254 | 19e88cb8 | Thomas ANDREJAK | |
255 | e307e626 | Francois POIROTTE | |
256 | class MaskedEventsSchema(schema.Schema): |
||
257 | e181e86c | Francois POIROTTE | """Schéma de validation de la méthode masked_events."""
|
258 | e307e626 | Francois POIROTTE | idcorrevent = validators.Int(not_empty=True)
|
259 | page = validators.Int(min=1, if_missing=1, if_invalid=1) |
||
260 | |||
261 | @validate(
|
||
262 | validators=MaskedEventsSchema(), |
||
263 | error_handler = process_form_errors) |
||
264 | 00d2e1d1 | Vincent QUEMENER | @expose('raw_events_table.html') |
265 | f2e30877 | Francois POIROTTE | @require(access_restriction)
|
266 | 02c4a1e7 | Francois POIROTTE | def masked_events(self, idcorrevent, page=1): |
267 | 54644278 | Francois POIROTTE | """
|
268 | e181e86c | Francois POIROTTE | Affichage de la liste des événements bruts masqués d'un événement
|
269 | corrélé (événements agrégés dans l'événement corrélé).
|
||
270 | 54644278 | Francois POIROTTE |
|
271 | 5a845c93 | Vincent QUEMENER | @param page: numéro de la page à afficher.
|
272 | @type page: C{int}
|
||
273 | e181e86c | Francois POIROTTE | @param idcorrevent: identifiant de l'événement corrélé souhaité.
|
274 | 5a845c93 | Vincent QUEMENER | @type idcorrevent: C{int}
|
275 | 54644278 | Francois POIROTTE | """
|
276 | f1886725 | Vincent QUEMENER | |
277 | # Auto-supervision
|
||
278 | self.get_failures()
|
||
279 | |||
280 | 195aa50d | Francois POIROTTE | user = get_current_user() |
281 | a05b9a37 | Francois POIROTTE | |
282 | # Récupère la liste des événements masqués de l'événement
|
||
283 | # corrélé donné par idcorrevent.
|
||
284 | 195aa50d | Francois POIROTTE | events = VigiboardRequest(user, False)
|
285 | 54644278 | Francois POIROTTE | events.add_table( |
286 | Event, |
||
287 | events.items.c.hostname, |
||
288 | events.items.c.servicename, |
||
289 | ) |
||
290 | 072f2a16 | Francois POIROTTE | events.add_join((EVENTSAGGREGATE_TABLE, \ |
291 | EVENTSAGGREGATE_TABLE.c.idevent == Event.idevent)) |
||
292 | events.add_join((CorrEvent, CorrEvent.idcorrevent == \ |
||
293 | EVENTSAGGREGATE_TABLE.c.idcorrevent)) |
||
294 | e3c52cfd | Aurelien BOMPARD | events.add_join((events.items, |
295 | 54644278 | Francois POIROTTE | Event.idsupitem == events.items.c.idsupitem)) |
296 | events.add_filter(Event.idevent != CorrEvent.idcause) |
||
297 | events.add_filter(CorrEvent.idcorrevent == idcorrevent) |
||
298 | bcf87133 | Francois POIROTTE | |
299 | a05b9a37 | Francois POIROTTE | # Récupère l'instance de SupItem associé à la cause de
|
300 | # l'événement corrélé. Cette instance est utilisé pour
|
||
301 | # obtenir le nom d'hôte/service auquel la cause est
|
||
302 | # rattachée (afin de fournir un contexte à l'utilisateur).
|
||
303 | hostname = None
|
||
304 | servicename = None
|
||
305 | cause_supitem = DBSession.query( |
||
306 | SupItem, |
||
307 | ).join( |
||
308 | (Event, Event.idsupitem == SupItem.idsupitem), |
||
309 | cf3c2494 | Vincent QUEMENER | (CorrEvent, Event.idevent == CorrEvent.idcause), |
310 | a05b9a37 | Francois POIROTTE | ).filter(CorrEvent.idcorrevent == idcorrevent |
311 | ).one() |
||
312 | |||
313 | if isinstance(cause_supitem, LowLevelService): |
||
314 | hostname = cause_supitem.host.name |
||
315 | servicename = cause_supitem.servicename |
||
316 | elif isinstance(cause_supitem, Host): |
||
317 | hostname = cause_supitem.name |
||
318 | |||
319 | 4b573169 | Francois POIROTTE | # Pagination des résultats
|
320 | events.generate_request() |
||
321 | 36f6910e | Francois POIROTTE | items_per_page = int(session.get('items_per_page', config['vigiboard_items_per_page'])) |
322 | 27140946 | Francois POIROTTE | page = paginate.Page(events.req, page=page, |
323 | items_per_page=items_per_page) |
||
324 | 4b573169 | Francois POIROTTE | |
325 | 54644278 | Francois POIROTTE | # Vérification que l'événement existe
|
326 | 4b573169 | Francois POIROTTE | if not page.item_count: |
327 | 54644278 | Francois POIROTTE | flash(_('No masked event or access denied'), 'error') |
328 | redirect('/')
|
||
329 | |||
330 | return dict( |
||
331 | 0c8b0e15 | Francois POIROTTE | idcorrevent = idcorrevent, |
332 | a05b9a37 | Francois POIROTTE | hostname = hostname, |
333 | servicename = servicename, |
||
334 | cf3c2494 | Vincent QUEMENER | plugins_data = {}, |
335 | 54644278 | Francois POIROTTE | page = page, |
336 | 2dbc5942 | Francois POIROTTE | search_form = create_search_form, |
337 | search = {}, |
||
338 | adb0e63f | Francois POIROTTE | fixed_search = {}, |
339 | 54644278 | Francois POIROTTE | ) |
340 | |||
341 | e307e626 | Francois POIROTTE | |
342 | class EventSchema(schema.Schema): |
||
343 | e181e86c | Francois POIROTTE | """Schéma de validation de la méthode event."""
|
344 | e307e626 | Francois POIROTTE | idevent = validators.Int(not_empty=True)
|
345 | page = validators.Int(min=1, if_missing=1, if_invalid=1) |
||
346 | |||
347 | @validate(
|
||
348 | validators=EventSchema(), |
||
349 | error_handler = process_form_errors) |
||
350 | 00d2e1d1 | Vincent QUEMENER | @expose('history_table.html') |
351 | f2e30877 | Francois POIROTTE | @require(access_restriction)
|
352 | 02c4a1e7 | Francois POIROTTE | def event(self, idevent, page=1): |
353 | 19e88cb8 | Thomas ANDREJAK | """
|
354 | 94f31908 | Francois POIROTTE | Affichage de l'historique d'un événement brut.
|
355 | 19e88cb8 | Thomas ANDREJAK | Pour accéder à cette page, l'utilisateur doit être authentifié.
|
356 |
|
||
357 | 94f31908 | Francois POIROTTE | @param idevent: identifiant de l'événement brut souhaité.
|
358 | @type idevent: C{int}
|
||
359 | e181e86c | Francois POIROTTE | @param page: numéro de la page à afficher.
|
360 | @type page: C{int}
|
||
361 | c9245ffc | Vincent QUEMENER |
|
362 | e181e86c | Francois POIROTTE | Cette méthode permet de satisfaire l'exigence
|
363 | VIGILO_EXIG_VIGILO_BAC_0080.
|
||
364 | 19e88cb8 | Thomas ANDREJAK | """
|
365 | f1886725 | Vincent QUEMENER | |
366 | # Auto-supervision
|
||
367 | self.get_failures()
|
||
368 | |||
369 | 195aa50d | Francois POIROTTE | user = get_current_user() |
370 | events = VigiboardRequest(user, False)
|
||
371 | 911069bc | Francois POIROTTE | events.add_table( |
372 | 539f69fc | Francois POIROTTE | Event, |
373 | 72ec8dbf | Francois POIROTTE | events.items.c.hostname.label('hostname'),
|
374 | events.items.c.servicename.label('servicename'),
|
||
375 | 911069bc | Francois POIROTTE | ) |
376 | 072f2a16 | Francois POIROTTE | events.add_join((EVENTSAGGREGATE_TABLE, \ |
377 | EVENTSAGGREGATE_TABLE.c.idevent == Event.idevent)) |
||
378 | events.add_join((CorrEvent, CorrEvent.idcorrevent == \ |
||
379 | EVENTSAGGREGATE_TABLE.c.idcorrevent)) |
||
380 | e3c52cfd | Aurelien BOMPARD | events.add_join((events.items, |
381 | bfd8ead8 | Vincent QUEMENER | Event.idsupitem == events.items.c.idsupitem)) |
382 | 94f31908 | Francois POIROTTE | events.add_filter(Event.idevent == idevent) |
383 | 539f69fc | Francois POIROTTE | |
384 | if events.num_rows() != 1: |
||
385 | flash(_('No such event or access denied'), 'error') |
||
386 | 19e88cb8 | Thomas ANDREJAK | redirect('/')
|
387 | 539f69fc | Francois POIROTTE | |
388 | 19e88cb8 | Thomas ANDREJAK | events.format_events(0, 1) |
389 | 539f69fc | Francois POIROTTE | events.generate_tmpl_context() |
390 | history = events.format_history() |
||
391 | |||
392 | 4b573169 | Francois POIROTTE | # Pagination des résultats
|
393 | 36f6910e | Francois POIROTTE | items_per_page = int(session.get('items_per_page', config['vigiboard_items_per_page'])) |
394 | 4b573169 | Francois POIROTTE | page = paginate.Page(history, page=page, items_per_page=items_per_page) |
395 | 72ec8dbf | Francois POIROTTE | event = events.req[0]
|
396 | |||
397 | 19e88cb8 | Thomas ANDREJAK | return dict( |
398 | 0c8b0e15 | Francois POIROTTE | idevent = idevent, |
399 | 72ec8dbf | Francois POIROTTE | hostname = event.hostname, |
400 | servicename = event.servicename, |
||
401 | cf3c2494 | Vincent QUEMENER | plugins_data = {}, |
402 | 539f69fc | Francois POIROTTE | page = page, |
403 | 2dbc5942 | Francois POIROTTE | search_form = create_search_form, |
404 | search = {}, |
||
405 | adb0e63f | Francois POIROTTE | fixed_search = {}, |
406 | 911069bc | Francois POIROTTE | ) |
407 | 19e88cb8 | Thomas ANDREJAK | |
408 | e307e626 | Francois POIROTTE | |
409 | class ItemSchema(schema.Schema): |
||
410 | e181e86c | Francois POIROTTE | """Schéma de validation de la méthode item."""
|
411 | 5a845c93 | Vincent QUEMENER | # Si on ne passe pas le paramètre "page" ou qu'on passe une valeur
|
412 | # invalide ou pas de valeur du tout, alors on affiche la 1ère page.
|
||
413 | e307e626 | Francois POIROTTE | page = validators.Int(min=1, if_missing=1, if_invalid=1) |
414 | 5a845c93 | Vincent QUEMENER | |
415 | # Paramètres de tri
|
||
416 | sort = validators.String(if_missing=None)
|
||
417 | order = validators.OneOf(['asc', 'desc'], if_missing='asc') |
||
418 | |||
419 | # L'hôte / service dont on doit afficher les évènements
|
||
420 | e307e626 | Francois POIROTTE | host = validators.String(not_empty=True)
|
421 | service = validators.String(if_missing=None)
|
||
422 | |||
423 | 24334b4b | Vincent QUEMENER | @validate(
|
424 | e307e626 | Francois POIROTTE | validators=ItemSchema(), |
425 | 6ab72614 | Vincent QUEMENER | error_handler = process_form_errors) |
426 | eab949e2 | Vincent QUEMENER | @expose('events_table.html') |
427 | f2e30877 | Francois POIROTTE | @require(access_restriction)
|
428 | 02c4a1e7 | Francois POIROTTE | def item(self, page=1, host=None, service=None, sort=None, order=None): |
429 | 19e88cb8 | Thomas ANDREJAK | """
|
430 | 539f69fc | Francois POIROTTE | Affichage de l'historique de l'ensemble des événements corrélés
|
431 | jamais ouverts sur l'hôte / service demandé.
|
||
432 | 19e88cb8 | Thomas ANDREJAK | Pour accéder à cette page, l'utilisateur doit être authentifié.
|
433 |
|
||
434 | e181e86c | Francois POIROTTE | @param page: Numéro de la page à afficher.
|
435 | 5a845c93 | Vincent QUEMENER | @type: C{int}
|
436 | 19e88cb8 | Thomas ANDREJAK | @param host: Nom de l'hôte souhaité.
|
437 | 5a845c93 | Vincent QUEMENER | @type: C{str}
|
438 | 19e88cb8 | Thomas ANDREJAK | @param service: Nom du service souhaité
|
439 | 5a845c93 | Vincent QUEMENER | @type: C{str}
|
440 | @param sort: Colonne de tri
|
||
441 | @type: C{str} or C{None}
|
||
442 | @param order: Ordre du tri (asc ou desc)
|
||
443 | @type: C{str} or C{None}
|
||
444 | c9245ffc | Vincent QUEMENER |
|
445 | e181e86c | Francois POIROTTE | Cette méthode permet de satisfaire l'exigence
|
446 | VIGILO_EXIG_VIGILO_BAC_0080.
|
||
447 | 19e88cb8 | Thomas ANDREJAK | """
|
448 | f1886725 | Vincent QUEMENER | |
449 | # Auto-supervision
|
||
450 | self.get_failures()
|
||
451 | |||
452 | 24334b4b | Vincent QUEMENER | idsupitem = SupItem.get_supitem(host, service) |
453 | 1a1e8c17 | Francois POIROTTE | if not idsupitem: |
454 | flash(_('No such host/service'), 'error') |
||
455 | redirect('/')
|
||
456 | 24334b4b | Vincent QUEMENER | |
457 | 195aa50d | Francois POIROTTE | user = get_current_user() |
458 | 5a845c93 | Vincent QUEMENER | aggregates = VigiboardRequest(user, False, sort=sort, order=order)
|
459 | 539f69fc | Francois POIROTTE | aggregates.add_table( |
460 | 911069bc | Francois POIROTTE | CorrEvent, |
461 | 539f69fc | Francois POIROTTE | aggregates.items.c.hostname, |
462 | aggregates.items.c.servicename, |
||
463 | 911069bc | Francois POIROTTE | ) |
464 | 539f69fc | Francois POIROTTE | aggregates.add_join((Event, CorrEvent.idcause == Event.idevent)) |
465 | 0842bb2c | Francois POIROTTE | aggregates.add_join((aggregates.items, |
466 | 539f69fc | Francois POIROTTE | Event.idsupitem == aggregates.items.c.idsupitem)) |
467 | aggregates.add_filter(aggregates.items.c.idsupitem == idsupitem) |
||
468 | baedcd0f | Francois POIROTTE | |
469 | 4b573169 | Francois POIROTTE | # Pagination des résultats
|
470 | aggregates.generate_request() |
||
471 | 36f6910e | Francois POIROTTE | items_per_page = int(session.get('items_per_page', config['vigiboard_items_per_page'])) |
472 | 27140946 | Francois POIROTTE | page = paginate.Page(aggregates.req, page=page, |
473 | items_per_page=items_per_page) |
||
474 | 4b573169 | Francois POIROTTE | |
475 | a2a22ade | Francois POIROTTE | # Vérification qu'il y a au moins 1 événement qui correspond
|
476 | 4b573169 | Francois POIROTTE | if not page.item_count: |
477 | 911069bc | Francois POIROTTE | flash(_('No access to this host/service or no event yet'), 'error') |
478 | 19e88cb8 | Thomas ANDREJAK | redirect('/')
|
479 | ee3ae8c8 | Francois POIROTTE | |
480 | 4b573169 | Francois POIROTTE | # Ajout des formulaires et préparation
|
481 | # des données pour ces formulaires.
|
||
482 | ids_events = [event[0].idcause for event in page.items] |
||
483 | 1c5486c7 | Francois POIROTTE | tmpl_context.last_modification = calendar.timegm( |
484 | get_last_modification_timestamp(ids_events).timetuple()) |
||
485 | 539f69fc | Francois POIROTTE | |
486 | 4b573169 | Francois POIROTTE | tmpl_context.edit_event_form = EditEventForm("edit_event_form",
|
487 | submit_text=_('Apply'), action=url('/update')) |
||
488 | e3c52cfd | Aurelien BOMPARD | |
489 | a2fa6a5b | Francois POIROTTE | plugins_data = {} |
490 | for plugin in dict(config['columns_plugins']): |
||
491 | plugins_data[plugin] = {} |
||
492 | |||
493 | 19e88cb8 | Thomas ANDREJAK | return dict( |
494 | 0c8b0e15 | Francois POIROTTE | hostname = host, |
495 | servicename = service, |
||
496 | a2fa6a5b | Francois POIROTTE | plugins_data = plugins_data, |
497 | 539f69fc | Francois POIROTTE | page = page, |
498 | 5a845c93 | Vincent QUEMENER | sort = sort, |
499 | order = order, |
||
500 | 54644278 | Francois POIROTTE | event_edit_status_options = edit_event_status_options, |
501 | 2dbc5942 | Francois POIROTTE | search_form = create_search_form, |
502 | search = {}, |
||
503 | adb0e63f | Francois POIROTTE | fixed_search = {}, |
504 | 54644278 | Francois POIROTTE | ) |
505 | 19e88cb8 | Thomas ANDREJAK | |
506 | e307e626 | Francois POIROTTE | |
507 | class UpdateSchema(schema.Schema): |
||
508 | e181e86c | Francois POIROTTE | """Schéma de validation de la méthode update."""
|
509 | e307e626 | Francois POIROTTE | id = validators.Regex(r'^[0-9]+(,[0-9]+)*,?$')
|
510 | last_modification = validators.Number(not_empty=True)
|
||
511 | trouble_ticket = validators.String(if_missing='')
|
||
512 | 9e0ea30e | Francois POIROTTE | ack = validators.OneOf( |
513 | [unicode(s[0]) for s in edit_event_status_options], |
||
514 | not_empty=True)
|
||
515 | e307e626 | Francois POIROTTE | |
516 | @validate(
|
||
517 | validators=UpdateSchema(), |
||
518 | error_handler = process_form_errors) |
||
519 | 9e0ea30e | Francois POIROTTE | @require(
|
520 | All( |
||
521 | not_anonymous(msg=l_("You need to be authenticated")),
|
||
522 | 73119f8a | Francois POIROTTE | Any(config.is_manager, |
523 | a5f99051 | Francois POIROTTE | has_permission('vigiboard-update'),
|
524 | 9e0ea30e | Francois POIROTTE | msg=l_("You don't have write access to VigiBoard"))
|
525 | )) |
||
526 | dcd79358 | Francois POIROTTE | @expose()
|
527 | a9a4679d | Francois POIROTTE | def update(self, id, last_modification, trouble_ticket, ack): |
528 | 19e88cb8 | Thomas ANDREJAK | """
|
529 | a2a22ade | Francois POIROTTE | Mise à jour d'un événement suivant les arguments passés.
|
530 | 8484b8bd | Francois POIROTTE | Cela peut être un changement de ticket ou un changement de statut.
|
531 | e3c52cfd | Aurelien BOMPARD |
|
532 | a9a4679d | Francois POIROTTE | @param id: Le ou les identifiants des événements à traiter
|
533 | @param last_modification: La date de la dernière modification
|
||
534 | 57387640 | Francois POIROTTE | dont l'utilisateur est au courant.
|
535 | a9a4679d | Francois POIROTTE | @param trouble_ticket: Nouveau numéro du ticket associé.
|
536 | @param ack: Nouvel état d'acquittement des événements sélectionnés.
|
||
537 | c9245ffc | Vincent QUEMENER |
|
538 | e3c52cfd | Aurelien BOMPARD | Cette méthode permet de satisfaire les exigences suivantes :
|
539 | e181e86c | Francois POIROTTE | - VIGILO_EXIG_VIGILO_BAC_0020,
|
540 | - VIGILO_EXIG_VIGILO_BAC_0060,
|
||
541 | - VIGILO_EXIG_VIGILO_BAC_0110.
|
||
542 | 19e88cb8 | Thomas ANDREJAK | """
|
543 | |||
544 | 97f6d842 | Vincent QUEMENER | # On vérifie que des identifiants ont bien été transmis via
|
545 | # le formulaire, et on informe l'utilisateur le cas échéant.
|
||
546 | a9a4679d | Francois POIROTTE | if id is None: |
547 | 10848680 | Francois POIROTTE | flash(_('No event has been selected'), 'warning') |
548 | a9a4679d | Francois POIROTTE | raise redirect(request.environ.get('HTTP_REFERER', '/')) |
549 | 5d20c2c5 | Francois POIROTTE | |
550 | 2b740fc8 | Francois POIROTTE | # On récupère la liste de tous les identifiants des événements
|
551 | # à mettre à jour.
|
||
552 | 8b2edebe | Aurelien BOMPARD | ids = [ int(i) for i in id.strip(',').split(',') ] |
553 | 195aa50d | Francois POIROTTE | |
554 | user = get_current_user() |
||
555 | 303419a6 | Francois POIROTTE | events = VigiboardRequest(user) |
556 | 915f3245 | Francois POIROTTE | events.add_table( |
557 | CorrEvent, |
||
558 | Event, |
||
559 | events.items.c.hostname, |
||
560 | events.items.c.servicename, |
||
561 | ) |
||
562 | 911069bc | Francois POIROTTE | events.add_join((Event, CorrEvent.idcause == Event.idevent)) |
563 | 0842bb2c | Francois POIROTTE | events.add_join((events.items, |
564 | bfd8ead8 | Vincent QUEMENER | Event.idsupitem == events.items.c.idsupitem)) |
565 | 780ca169 | Francois POIROTTE | events.add_filter(CorrEvent.idcorrevent.in_(ids)) |
566 | e3c52cfd | Aurelien BOMPARD | |
567 | 5edd29ac | Vincent QUEMENER | events.generate_request() |
568 | 915f3245 | Francois POIROTTE | idevents = [event[0].idcause for event in events.req] |
569 | a9a4679d | Francois POIROTTE | |
570 | 0842bb2c | Francois POIROTTE | # Si des changements sont survenus depuis que la
|
571 | 5edd29ac | Vincent QUEMENER | # page est affichée, on en informe l'utilisateur.
|
572 | 1c5486c7 | Francois POIROTTE | last_modification = datetime.utcfromtimestamp(last_modification) |
573 | a9a4679d | Francois POIROTTE | cur_last_modification = get_last_modification_timestamp(idevents, None)
|
574 | if cur_last_modification and last_modification < cur_last_modification: |
||
575 | 5edd29ac | Vincent QUEMENER | flash(_('Changes have occurred since the page was last displayed, '
|
576 | 'your changes HAVE NOT been saved.'), 'warning') |
||
577 | a9a4679d | Francois POIROTTE | raise redirect(request.environ.get('HTTP_REFERER', '/')) |
578 | f744bc14 | Francois POIROTTE | |
579 | 19e88cb8 | Thomas ANDREJAK | # Vérification que au moins un des identifiants existe et est éditable
|
580 | 94f31908 | Francois POIROTTE | if not events.num_rows(): |
581 | 19e88cb8 | Thomas ANDREJAK | flash(_('No access to this event'), 'error') |
582 | redirect('/')
|
||
583 | 8484b8bd | Francois POIROTTE | |
584 | 2b740fc8 | Francois POIROTTE | if ack == u'Forced': |
585 | condition = Any( |
||
586 | 73119f8a | Francois POIROTTE | config.is_manager, |
587 | 2b740fc8 | Francois POIROTTE | has_permission('vigiboard-admin'),
|
588 | msg=l_("You don't have administrative access "
|
||
589 | "to VigiBoard"))
|
||
590 | try:
|
||
591 | condition.check_authorization(request.environ) |
||
592 | 0dff1e21 | Francois POIROTTE | except NotAuthorizedError as e: |
593 | 2b740fc8 | Francois POIROTTE | reason = unicode(e)
|
594 | flash(reason, 'error')
|
||
595 | raise redirect(request.environ.get('HTTP_REFERER', '/')) |
||
596 | |||
597 | 915f3245 | Francois POIROTTE | # Si un module de gestion de ticket est utilisé,
|
598 | # il a la possibilité de changer à la volée le libellé du ticket.
|
||
599 | if self._tickets: |
||
600 | trouble_ticket = self._tickets.createTicket(events.req, trouble_ticket)
|
||
601 | |||
602 | 8ba2de75 | Francois POIROTTE | # Définit 2 mappings dont les ensembles sont disjoincts
|
603 | # pour basculer entre la représentation en base de données
|
||
604 | # et la représentation "humaine" du bac à événements.
|
||
605 | ack_mapping = { |
||
606 | # Permet d'associer la valeur dans le widget ToscaWidgets
|
||
607 | # (cf. vigiboard.widgets.edit_event.edit_event_status_options)
|
||
608 | # avec la valeur dans la base de données.
|
||
609 | u'None': CorrEvent.ACK_NONE,
|
||
610 | u'Acknowledged': CorrEvent.ACK_KNOWN,
|
||
611 | u'AAClosed': CorrEvent.ACK_CLOSED,
|
||
612 | |||
613 | # Permet d'afficher un libellé plus sympathique pour l'utilisateur
|
||
614 | # représentant l'état d'acquittement stocké en base de données.
|
||
615 | CorrEvent.ACK_NONE: l_('None'),
|
||
616 | CorrEvent.ACK_KNOWN: l_('Acknowledged'),
|
||
617 | CorrEvent.ACK_CLOSED: l_('Acknowledged and closed'),
|
||
618 | } |
||
619 | |||
620 | 2b740fc8 | Francois POIROTTE | # Modification des événements et création d'un historique
|
621 | # chaque fois que cela est nécessaire.
|
||
622 | 915f3245 | Francois POIROTTE | for data in events.req: |
623 | event = data[0]
|
||
624 | f744bc14 | Francois POIROTTE | if trouble_ticket and trouble_ticket != event.trouble_ticket: |
625 | 8484b8bd | Francois POIROTTE | history = EventHistory( |
626 | 3f7736d0 | Francois POIROTTE | type_action=u"Ticket change",
|
627 | 8484b8bd | Francois POIROTTE | idevent=event.idcause, |
628 | a9a4679d | Francois POIROTTE | value=unicode(trouble_ticket),
|
629 | 2b740fc8 | Francois POIROTTE | text="Changed trouble ticket from '%(from)s' "
|
630 | "to '%(to)s'" % {
|
||
631 | 'from': event.trouble_ticket,
|
||
632 | 'to': trouble_ticket,
|
||
633 | }, |
||
634 | e1133e5a | Francois POIROTTE | username=user.user_name, |
635 | 1c5486c7 | Francois POIROTTE | timestamp=datetime.utcnow(), |
636 | 8484b8bd | Francois POIROTTE | ) |
637 | 0842bb2c | Francois POIROTTE | DBSession.add(history) |
638 | 7f26a756 | Francois POIROTTE | LOGGER.info(_('User "%(user)s" (%(address)s) changed the '
|
639 | 'trouble ticket from "%(previous)s" to "%(new)s" '
|
||
640 | 'on event #%(idevent)d') % {
|
||
641 | 'user': request.identity['repoze.who.userid'], |
||
642 | 'address': request.remote_addr,
|
||
643 | 'previous': event.trouble_ticket,
|
||
644 | 'new': trouble_ticket,
|
||
645 | 'idevent': event.idcause,
|
||
646 | }) |
||
647 | a9a4679d | Francois POIROTTE | event.trouble_ticket = trouble_ticket |
648 | 8484b8bd | Francois POIROTTE | |
649 | 9e0ea30e | Francois POIROTTE | # Changement du statut d'acquittement.
|
650 | if ack != u'NoChange': |
||
651 | 2b740fc8 | Francois POIROTTE | changed_ack = ack |
652 | 9e0ea30e | Francois POIROTTE | # Pour forcer l'acquittement d'un événement,
|
653 | # il faut en plus avoir la permission
|
||
654 | # "vigiboard-admin".
|
||
655 | if ack == u'Forced': |
||
656 | 2b740fc8 | Francois POIROTTE | changed_ack = u'AAClosed'
|
657 | 7e0c4383 | Francois POIROTTE | cause = event.cause |
658 | f8020955 | Francois POIROTTE | # On met systématiquement l'événement à l'état "OK",
|
659 | # même s'il s'agit d'un hôte.
|
||
660 | # Techniquement, c'est incorrect, mais on fait ça
|
||
661 | # pour masquer l'événement de toutes façons...
|
||
662 | 7e0c4383 | Francois POIROTTE | cause.current_state = \ |
663 | 2b740fc8 | Francois POIROTTE | StateName.statename_to_value(u'OK')
|
664 | |||
665 | f8020955 | Francois POIROTTE | # Mise à jour de l'état dans State, pour que
|
666 | # VigiMap soit également mis à jour.
|
||
667 | DBSession.query(State).filter( |
||
668 | 7e0c4383 | Francois POIROTTE | State.idsupitem == cause.idsupitem, |
669 | f8020955 | Francois POIROTTE | ).update({ |
670 | 'state': StateName.statename_to_value(u'OK'), |
||
671 | }) |
||
672 | |||
673 | 2b740fc8 | Francois POIROTTE | history = EventHistory( |
674 | 3f7736d0 | Francois POIROTTE | type_action=u"Forced change state",
|
675 | 2b740fc8 | Francois POIROTTE | idevent=event.idcause, |
676 | value=u'OK',
|
||
677 | text="Forced state to 'OK'",
|
||
678 | username=user.user_name, |
||
679 | 1c5486c7 | Francois POIROTTE | timestamp=datetime.utcnow(), |
680 | caa4b302 | Francois POIROTTE | state=StateName.statename_to_value(u'OK'),
|
681 | 2b740fc8 | Francois POIROTTE | ) |
682 | DBSession.add(history) |
||
683 | 7f26a756 | Francois POIROTTE | LOGGER.info(_('User "%(user)s" (%(address)s) forcefully '
|
684 | 'closed event #%(idevent)d') % {
|
||
685 | 'user': request. \
|
||
686 | identity['repoze.who.userid'],
|
||
687 | 'address': request.remote_addr,
|
||
688 | 'idevent': event.idcause,
|
||
689 | }) |
||
690 | ddbaec88 | Francois POIROTTE | |
691 | 8ba2de75 | Francois POIROTTE | # Convertit la valeur du widget ToscaWidgets
|
692 | # vers le code interne puis vers un libellé
|
||
693 | # "humain".
|
||
694 | ack_label = ack_mapping[ack_mapping[changed_ack]] |
||
695 | |||
696 | # Si le changement a été forcé,
|
||
697 | # on veut le mettre en évidence.
|
||
698 | if ack == u'Forced': |
||
699 | 3f7736d0 | Francois POIROTTE | history_label = u'Forced'
|
700 | 8ba2de75 | Francois POIROTTE | else:
|
701 | history_label = ack_label |
||
702 | |||
703 | 19e88cb8 | Thomas ANDREJAK | history = EventHistory( |
704 | 3f7736d0 | Francois POIROTTE | type_action=u"Acknowledgement change state",
|
705 | 8484b8bd | Francois POIROTTE | idevent=event.idcause, |
706 | 8ba2de75 | Francois POIROTTE | value=unicode(history_label),
|
707 | 2cf703a5 | Francois POIROTTE | text=u"Changed acknowledgement status "
|
708 | u"from '%s' to '%s'" % (
|
||
709 | 8ba2de75 | Francois POIROTTE | ack_mapping[event.ack], |
710 | ack_label, |
||
711 | ee3ae8c8 | Francois POIROTTE | ), |
712 | e1133e5a | Francois POIROTTE | username=user.user_name, |
713 | 1c5486c7 | Francois POIROTTE | timestamp=datetime.utcnow(), |
714 | 8484b8bd | Francois POIROTTE | ) |
715 | 19e88cb8 | Thomas ANDREJAK | DBSession.add(history) |
716 | 7f26a756 | Francois POIROTTE | LOGGER.info(_('User "%(user)s" (%(address)s) changed the state '
|
717 | 'from "%(previous)s" to "%(new)s" on event '
|
||
718 | '#%(idevent)d') % {
|
||
719 | 'user': request.identity['repoze.who.userid'], |
||
720 | 'address': request.remote_addr,
|
||
721 | 8ba2de75 | Francois POIROTTE | 'previous': _(ack_mapping[event.ack]),
|
722 | 'new': _(ack_label),
|
||
723 | 7f26a756 | Francois POIROTTE | 'idevent': event.idcause,
|
724 | }) |
||
725 | 8ba2de75 | Francois POIROTTE | event.ack = ack_mapping[changed_ack] |
726 | 3d0d254c | Francois POIROTTE | |
727 | 10848680 | Francois POIROTTE | DBSession.flush() |
728 | 19e88cb8 | Thomas ANDREJAK | flash(_('Updated successfully'))
|
729 | a9a4679d | Francois POIROTTE | redirect(request.environ.get('HTTP_REFERER', '/')) |
730 | 19e88cb8 | Thomas ANDREJAK | |
731 | e307e626 | Francois POIROTTE | |
732 | class GetPluginValueSchema(schema.Schema): |
||
733 | e181e86c | Francois POIROTTE | """Schéma de validation de la méthode get_plugin_value."""
|
734 | e307e626 | Francois POIROTTE | idcorrevent = validators.Int(not_empty=True)
|
735 | 65383903 | Francois POIROTTE | plugin_name = validators.String(not_empty=True)
|
736 | e307e626 | Francois POIROTTE | # Permet de passer des paramètres supplémentaires au plugin.
|
737 | allow_extra_fields = True
|
||
738 | |||
739 | @validate(
|
||
740 | validators=GetPluginValueSchema(), |
||
741 | 4c08cd96 | Francois POIROTTE | error_handler = handle_validation_errors_json) |
742 | 8ad24667 | Thomas ANDREJAK | @expose('json') |
743 | f2e30877 | Francois POIROTTE | @require(access_restriction)
|
744 | cf3c2494 | Vincent QUEMENER | def plugin_json(self, idcorrevent, plugin_name, *arg, **krgv): |
745 | 8ad24667 | Thomas ANDREJAK | """
|
746 | 4dd2035e | Francois POIROTTE | Permet de récupérer la valeur d'un plugin associée à un CorrEvent
|
747 | donné via JSON.
|
||
748 | 8ad24667 | Thomas ANDREJAK | """
|
749 | 6520dbc0 | Vincent QUEMENER | |
750 | # Vérification de l'existence du plugin
|
||
751 | 65383903 | Francois POIROTTE | plugins = dict(config['columns_plugins']) |
752 | if plugin_name not in plugins: |
||
753 | raise HTTPNotFound(_("No such plugin '%s'") % plugin_name) |
||
754 | |||
755 | f8f519ac | Vincent QUEMENER | # Récupération de la liste des évènements corrélés
|
756 | events = DBSession.query(CorrEvent.idcorrevent) |
||
757 | |||
758 | # Filtrage des évènements en fonction des permissions de
|
||
759 | # l'utilisateur (s'il n'appartient pas au groupe 'managers')
|
||
760 | 73119f8a | Francois POIROTTE | if not config.is_manager.is_met(request.environ): |
761 | 9f441867 | Vincent QUEMENER | user = get_current_user() |
762 | |||
763 | f8f519ac | Vincent QUEMENER | events = events.join( |
764 | 9f441867 | Vincent QUEMENER | (Event, Event.idevent == CorrEvent.idcause), |
765 | ).outerjoin( |
||
766 | (LowLevelService, LowLevelService.idservice == Event.idsupitem), |
||
767 | ).join( |
||
768 | (SUPITEM_GROUP_TABLE, |
||
769 | or_( |
||
770 | SUPITEM_GROUP_TABLE.c.idsupitem == \ |
||
771 | LowLevelService.idhost, |
||
772 | SUPITEM_GROUP_TABLE.c.idsupitem == \ |
||
773 | Event.idsupitem, |
||
774 | ) |
||
775 | ), |
||
776 | ).join( |
||
777 | f8f519ac | Vincent QUEMENER | (GroupHierarchy, |
778 | GroupHierarchy.idchild == SUPITEM_GROUP_TABLE.c.idgroup), |
||
779 | 9f441867 | Vincent QUEMENER | ).join( |
780 | f8f519ac | Vincent QUEMENER | (DataPermission, |
781 | DataPermission.idgroup == GroupHierarchy.idparent), |
||
782 | 9f441867 | Vincent QUEMENER | ).join( |
783 | f8f519ac | Vincent QUEMENER | (USER_GROUP_TABLE, |
784 | USER_GROUP_TABLE.c.idgroup == DataPermission.idusergroup), |
||
785 | ).filter(USER_GROUP_TABLE.c.username == user.user_name) |
||
786 | |||
787 | # Filtrage des évènements en fonction
|
||
788 | # de l'identifiant passé en paramètre
|
||
789 | events = events.filter(CorrEvent.idcorrevent == idcorrevent).count() |
||
790 | |||
791 | # Pas d'événement ou permission refusée. On ne distingue pas
|
||
792 | # les 2 cas afin d'éviter la divulgation d'informations.
|
||
793 | if events == 0: |
||
794 | raise HTTPNotFound(_('No such incident or insufficient ' |
||
795 | 'permissions'))
|
||
796 | |||
797 | # L'évènement existe bien, et l'utilisateur dispose
|
||
798 | # des permissions appropriées. On fait alors appel au
|
||
799 | # plugin pour récupérer les informations à retourner.
|
||
800 | cf3c2494 | Vincent QUEMENER | return plugins[plugin_name].get_json_data(idcorrevent, *arg, **krgv)
|
801 | 1bb369b9 | Francois POIROTTE | |
802 | @validate(validators={
|
||
803 | "fontsize": validators.Regex(
|
||
804 | r'[0-9]+(pt|px|em|%)',
|
||
805 | 6ab72614 | Vincent QUEMENER | regexOps = ('I',)
|
806 | 4c08cd96 | Francois POIROTTE | )}, error_handler = handle_validation_errors_json) |
807 | 693e96f1 | Thomas ANDREJAK | @expose('json') |
808 | b8500d1a | Thomas ANDREJAK | def set_fontsize(self, fontsize): |
809 | 4dd2035e | Francois POIROTTE | """Enregistre la taille de la police dans les préférences."""
|
810 | b8500d1a | Thomas ANDREJAK | session['fontsize'] = fontsize
|
811 | session.save() |
||
812 | e2e218d7 | Francois POIROTTE | return dict() |
813 | 693e96f1 | Thomas ANDREJAK | |
814 | 08d86103 | Francois POIROTTE | @validate(validators={"refresh": validators.Int()}, |
815 | 4c08cd96 | Francois POIROTTE | error_handler = handle_validation_errors_json) |
816 | 693e96f1 | Thomas ANDREJAK | @expose('json') |
817 | b8500d1a | Thomas ANDREJAK | def set_refresh(self, refresh): |
818 | 4dd2035e | Francois POIROTTE | """Enregistre le temps de rafraichissement dans les préférences."""
|
819 | 8d822583 | Francois POIROTTE | session['refresh'] = bool(refresh) |
820 | b8500d1a | Thomas ANDREJAK | session.save() |
821 | e2e218d7 | Francois POIROTTE | return dict() |
822 | |||
823 | @expose('json') |
||
824 | def set_theme(self, theme): |
||
825 | 4dd2035e | Francois POIROTTE | """Enregistre le thème à utiliser dans les préférences."""
|
826 | # On sauvegarde l'ID du thème sans vérifications
|
||
827 | # car les thèmes (styles CSS) sont définies dans
|
||
828 | # les packages de thèmes (ex: vigilo-themes-default).
|
||
829 | # La vérification de la valeur est faite dans les templates.
|
||
830 | e2e218d7 | Francois POIROTTE | session['theme'] = theme
|
831 | session.save() |
||
832 | return dict() |
||
833 | 2b740fc8 | Francois POIROTTE | |
834 | 36f6910e | Francois POIROTTE | @validate(validators={"items": validators.Int()}, |
835 | error_handler = handle_validation_errors_json) |
||
836 | @expose('json') |
||
837 | def set_items_per_page(self, items): |
||
838 | """Enregistre le nombre d'alertes par page dans les préférences."""
|
||
839 | session['items_per_page'] = items
|
||
840 | session.save() |
||
841 | return dict() |
||
842 | |||
843 | ea0e5dfb | Francois POIROTTE | @require(access_restriction)
|
844 | @expose('json') |
||
845 | aa6e5fe9 | Aurelien BOMPARD | def get_groups(self, parent_id=None, onlytype="", offset=0, noCache=None): |
846 | 48acee1e | Francois POIROTTE | """
|
847 | Affiche un étage de l'arbre de
|
||
848 | sélection des hôtes et groupes d'hôtes.
|
||
849 |
|
||
850 | @param parent_id: identifiant du groupe d'hôte parent
|
||
851 | @type parent_id: C{int} or None
|
||
852 | """
|
||
853 | |||
854 | # Si l'identifiant du groupe parent n'est pas
|
||
855 | 70938860 | Vincent QUEMENER | # spécifié, on retourne la liste des groupes
|
856 | # racines, fournie par la méthode get_root_groups.
|
||
857 | 48acee1e | Francois POIROTTE | if parent_id is None: |
858 | 70938860 | Vincent QUEMENER | return self.get_root_groups() |
859 | 48acee1e | Francois POIROTTE | |
860 | 0bd9c069 | Francois POIROTTE | # TODO: Utiliser un schéma de validation
|
861 | parent_id = int(parent_id)
|
||
862 | aa6e5fe9 | Aurelien BOMPARD | offset = int(offset)
|
863 | ea0e5dfb | Francois POIROTTE | |
864 | cf3c2494 | Vincent QUEMENER | # On récupère la liste des groupes de supitems dont
|
865 | # l'identifiant du parent est passé en paramètre.
|
||
866 | supitem_groups = DBSession.query( |
||
867 | SupItemGroup.idgroup, |
||
868 | SupItemGroup.name, |
||
869 | ).join( |
||
870 | (GroupHierarchy, |
||
871 | GroupHierarchy.idchild == SupItemGroup.idgroup), |
||
872 | ).filter(GroupHierarchy.idparent == parent_id |
||
873 | 837cb99f | Vincent QUEMENER | ).filter(GroupHierarchy.hops == 1
|
874 | ).order_by(SupItemGroup.name) |
||
875 | cf3c2494 | Vincent QUEMENER | |
876 | # Si l'utilisateur n'appartient pas au groupe 'managers',
|
||
877 | # on filtre les résultats en fonction de ses permissions.
|
||
878 | 73119f8a | Francois POIROTTE | if not config.is_manager.is_met(request.environ): |
879 | 0bd9c069 | Francois POIROTTE | user = get_current_user() |
880 | eec46cb0 | Vincent QUEMENER | GroupHierarchy_aliased = aliased(GroupHierarchy, |
881 | name='GroupHierarchy_aliased')
|
||
882 | 70938860 | Vincent QUEMENER | supitem_groups = supitem_groups.join( |
883 | cf3c2494 | Vincent QUEMENER | (GroupHierarchy_aliased, |
884 | 70938860 | Vincent QUEMENER | or_( |
885 | GroupHierarchy_aliased.idchild == SupItemGroup.idgroup, |
||
886 | GroupHierarchy_aliased.idparent == SupItemGroup.idgroup |
||
887 | )), |
||
888 | cf3c2494 | Vincent QUEMENER | (DataPermission, |
889 | 70938860 | Vincent QUEMENER | or_( |
890 | DataPermission.idgroup == \ |
||
891 | GroupHierarchy_aliased.idparent, |
||
892 | DataPermission.idgroup == \ |
||
893 | GroupHierarchy_aliased.idchild, |
||
894 | )), |
||
895 | cf3c2494 | Vincent QUEMENER | (USER_GROUP_TABLE, USER_GROUP_TABLE.c.idgroup == \ |
896 | DataPermission.idusergroup), |
||
897 | ).filter(USER_GROUP_TABLE.c.username == user.user_name) |
||
898 | eec46cb0 | Vincent QUEMENER | |
899 | aa6e5fe9 | Aurelien BOMPARD | limit = int(config.get("max_menu_entries", 20)) |
900 | result = {"groups": [], "items": []} |
||
901 | num_children_left = supitem_groups.distinct().count() - offset |
||
902 | if offset:
|
||
903 | result["continued_from"] = offset
|
||
904 | result["continued_type"] = "group" |
||
905 | all_grs = supitem_groups.distinct().limit(limit).offset(offset).all() |
||
906 | for group in all_grs: |
||
907 | result["groups"].append({
|
||
908 | 48acee1e | Francois POIROTTE | 'id' : group.idgroup,
|
909 | 'name' : group.name,
|
||
910 | aa6e5fe9 | Aurelien BOMPARD | 'type' : "group", |
911 | }) |
||
912 | if num_children_left > limit:
|
||
913 | result["groups"].append({
|
||
914 | 'name': _("Next %(limit)s") % {"limit": limit}, |
||
915 | 'offset': offset + limit,
|
||
916 | 'parent_id': parent_id,
|
||
917 | 'type': 'continued', |
||
918 | 'for_type': 'group', |
||
919 | 48acee1e | Francois POIROTTE | }) |
920 | |||
921 | aa6e5fe9 | Aurelien BOMPARD | return result
|
922 | 48acee1e | Francois POIROTTE | |
923 | 70938860 | Vincent QUEMENER | def get_root_groups(self): |
924 | 48acee1e | Francois POIROTTE | """
|
925 | Retourne tous les groupes racines (c'est à dire n'ayant
|
||
926 | aucun parent) d'hôtes auquel l'utilisateur a accès.
|
||
927 |
|
||
928 | @return: Un dictionnaire contenant la liste de ces groupes.
|
||
929 | @rtype : C{dict} of C{list} of C{dict} of C{mixed}
|
||
930 | """
|
||
931 | ea0e5dfb | Francois POIROTTE | |
932 | 0bd9c069 | Francois POIROTTE | # On récupère tous les groupes qui ont un parent.
|
933 | children = DBSession.query( |
||
934 | SupItemGroup, |
||
935 | ).distinct( |
||
936 | ).join( |
||
937 | (GroupHierarchy, GroupHierarchy.idchild == SupItemGroup.idgroup) |
||
938 | ).filter(GroupHierarchy.hops > 0)
|
||
939 | |||
940 | # Ensuite on les exclut de la liste des groupes,
|
||
941 | # pour ne garder que ceux qui sont au sommet de
|
||
942 | # l'arbre et qui constituent nos "root groups".
|
||
943 | root_groups = DBSession.query( |
||
944 | SupItemGroup, |
||
945 | ).except_(children |
||
946 | ).order_by(SupItemGroup.name) |
||
947 | 48acee1e | Francois POIROTTE | |
948 | # On filtre ces groupes racines afin de ne
|
||
949 | # retourner que ceux auquels l'utilisateur a accès
|
||
950 | user = get_current_user() |
||
951 | 73119f8a | Francois POIROTTE | if not config.is_manager.is_met(request.environ): |
952 | eec46cb0 | Vincent QUEMENER | root_groups = root_groups.join( |
953 | (GroupHierarchy, |
||
954 | 70938860 | Vincent QUEMENER | GroupHierarchy.idparent == SupItemGroup.idgroup), |
955 | eec46cb0 | Vincent QUEMENER | (DataPermission, |
956 | 70938860 | Vincent QUEMENER | DataPermission.idgroup == GroupHierarchy.idchild), |
957 | eec46cb0 | Vincent QUEMENER | (USER_GROUP_TABLE, USER_GROUP_TABLE.c.idgroup == \ |
958 | DataPermission.idusergroup), |
||
959 | ).filter(USER_GROUP_TABLE.c.username == user.user_name) |
||
960 | 48acee1e | Francois POIROTTE | |
961 | groups = [] |
||
962 | 0bd9c069 | Francois POIROTTE | for group in root_groups.all(): |
963 | 48acee1e | Francois POIROTTE | groups.append({ |
964 | 'id' : group.idgroup,
|
||
965 | 'name' : group.name,
|
||
966 | aa6e5fe9 | Aurelien BOMPARD | 'type' : "group", |
967 | 48acee1e | Francois POIROTTE | }) |
968 | |||
969 | aa6e5fe9 | Aurelien BOMPARD | return dict(groups=groups, items=[]) |
970 | 48acee1e | Francois POIROTTE | |
971 | 0842bb2c | Francois POIROTTE | def get_last_modification_timestamp(event_id_list, |
972 | c1f83918 | Francois POIROTTE | value_if_none=datetime.utcnow): |
973 | 97f6d842 | Vincent QUEMENER | """
|
974 | 0842bb2c | Francois POIROTTE | Récupère le timestamp de la dernière modification
|
975 | 97f6d842 | Vincent QUEMENER | opérée sur l'un des événements dont l'identifiant
|
976 | fait partie de la liste passée en paramètre.
|
||
977 | """
|
||
978 | 5a845c93 | Vincent QUEMENER | if not event_id_list: |
979 | last_modification_timestamp = None
|
||
980 | else:
|
||
981 | last_modification_timestamp = DBSession.query( |
||
982 | 97f6d842 | Vincent QUEMENER | func.max(EventHistory.timestamp), |
983 | ).filter(EventHistory.idevent.in_(event_id_list) |
||
984 | ).scalar() |
||
985 | 5a845c93 | Vincent QUEMENER | |
986 | e9ccb711 | Francois POIROTTE | if not last_modification_timestamp: |
987 | c1f83918 | Francois POIROTTE | if not callable(value_if_none): |
988 | return value_if_none
|
||
989 | 24334b4b | Vincent QUEMENER | else:
|
990 | c1f83918 | Francois POIROTTE | last_modification_timestamp = value_if_none() |
991 | return last_modification_timestamp |