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