Revision 24334b4b
Ajout de l'affichage des évènements corrélés causés par des incidents sur des hôtes.
git-svn-id: https://vigilo-dev.si.c-s.fr/svn@1714 b22e2e97-25c9-44ff-b637-2e5ceca36478
vigiboard/controllers/root.py | ||
---|---|---|
8 | 8 |
from pylons.i18n import ugettext as _ |
9 | 9 |
from pylons.i18n import lazy_ugettext as l_ |
10 | 10 |
from pylons.controllers.util import abort |
11 |
from sqlalchemy import not_, and_, asc |
|
11 |
from sqlalchemy import not_, and_, or_, asc
|
|
12 | 12 |
from sqlalchemy.orm import aliased |
13 | 13 |
from sqlalchemy.sql import func |
14 | 14 |
from datetime import datetime |
... | ... | |
20 | 20 |
from vigiboard.model import Event, EventHistory, CorrEvent, \ |
21 | 21 |
Host, HostGroup, ServiceGroup, \ |
22 | 22 |
StateName, User, ServiceLowLevel |
23 |
from vigilo.models import SupItem |
|
23 | 24 |
from repoze.what.predicates import Any, not_anonymous |
24 | 25 |
from vigiboard.widgets.edit_event import edit_event_status_options |
25 | 26 |
from vigiboard.controllers.vigiboardrequest import VigiboardRequest |
... | ... | |
103 | 104 |
if hostgroup: |
104 | 105 |
search['hostgroup'] = hostgroup |
105 | 106 |
hostgroup = sql_escape_like(hostgroup) |
106 |
hg_alias = aliased(HostGroup) |
|
107 |
aggregates.add_outer_join((hg_alias, hg_alias.idgroup == \ |
|
108 |
HOST_GROUP_TABLE.c.idgroup)) |
|
109 |
aggregates.add_filter(hg_alias.name.ilike('%%%s%%' % hostgroup)) |
|
107 |
aggregates.add_join((HostGroup, HostGroup.idgroup == \ |
|
108 |
aggregates.items.c.idhostgroup)) |
|
109 |
aggregates.add_filter(HostGroup.name.ilike('%%%s%%' % hostgroup)) |
|
110 | 110 |
|
111 | 111 |
if servicegroup: |
112 | 112 |
search['servicegroup'] = servicegroup |
113 | 113 |
servicegroup = sql_escape_like(servicegroup) |
114 |
sg_alias = aliased(ServiceGroup) |
|
115 |
aggregates.add_outer_join((sg_alias, sg_alias.idgroup == \ |
|
116 |
SERVICE_GROUP_TABLE.c.idgroup)) |
|
117 |
aggregates.add_filter(sg_alias.name.ilike( |
|
118 |
'%%%s%%' % servicegroup)) |
|
114 |
aggregates.add_join((ServiceGroup, ServiceGroup.idgroup == \ |
|
115 |
aggregates.items.c.idservicegroup)) |
|
116 |
aggregates.add_filter(ServiceGroup.name.ilike('%%%s%%' % servicegroup)) |
|
119 | 117 |
|
120 | 118 |
if host: |
121 | 119 |
search['host'] = host |
122 | 120 |
host = sql_escape_like(host) |
123 |
aggregates.add_filter(Host.name.ilike('%%%s%%' % host)) |
|
121 |
aggregates.add_filter(aggregates.items.c.hostname.ilike( |
|
122 |
'%%%s%%' % host)) |
|
124 | 123 |
|
125 | 124 |
if service: |
126 | 125 |
search['service'] = service |
127 | 126 |
service = sql_escape_like(service) |
128 |
aggregates.add_filter(ServiceLowLevel.servicename.ilike(
|
|
127 |
aggregates.add_filter(aggregates.items.c.servicename.ilike(
|
|
129 | 128 |
'%%%s%%' % service)) |
130 | 129 |
|
131 | 130 |
if output: |
... | ... | |
213 | 212 |
user_groups = user.groups |
214 | 213 |
|
215 | 214 |
# try: |
215 |
|
|
216 |
lls_query = DBSession.query( |
|
217 |
ServiceLowLevel.idservice.label("idsupitem"), |
|
218 |
ServiceLowLevel.servicename, |
|
219 |
Host.name.label("hostname") |
|
220 |
).join( |
|
221 |
(Host, Host.idhost == ServiceLowLevel.idhost), |
|
222 |
).outerjoin( |
|
223 |
(HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == ServiceLowLevel.idservice), |
|
224 |
(SERVICE_GROUP_TABLE, SERVICE_GROUP_TABLE.c.idservice == ServiceLowLevel.idservice), |
|
225 |
).filter( |
|
226 |
or_( |
|
227 |
HOST_GROUP_TABLE.c.idgroup.in_(user_groups), |
|
228 |
SERVICE_GROUP_TABLE.c.idgroup.in_(user_groups), |
|
229 |
), |
|
230 |
) |
|
231 |
|
|
232 |
host_query = DBSession.query( |
|
233 |
Host.idhost.label("idsupitem"), |
|
234 |
"NULL", |
|
235 |
Host.name.label("hostname") |
|
236 |
).join((HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == Host.idhost) |
|
237 |
).filter(HOST_GROUP_TABLE.c.idgroup.in_(user_groups), |
|
238 |
) |
|
239 |
|
|
240 |
items = lls_query.union(host_query).subquery() |
|
241 |
|
|
216 | 242 |
event = DBSession.query( |
217 | 243 |
CorrEvent.priority, |
218 | 244 |
Event, |
245 |
items.c.hostname, |
|
246 |
items.c.servicename, |
|
219 | 247 |
).join( |
220 | 248 |
(Event, CorrEvent.idcause == Event.idevent), |
221 |
(ServiceLowLevel, Event.idsupitem == \ |
|
222 |
ServiceLowLevel.idservice), |
|
223 |
(Host, Host.idhost == ServiceLowLevel.idhost), |
|
224 |
(HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == \ |
|
225 |
Host.idhost), |
|
226 |
(SERVICE_GROUP_TABLE, SERVICE_GROUP_TABLE.c.idservice == \ |
|
227 |
ServiceLowLevel.idservice), |
|
228 |
).filter(HOST_GROUP_TABLE.c.idgroup.in_(user_groups) |
|
229 |
).filter(SERVICE_GROUP_TABLE.c.idgroup.in_(user_groups) |
|
249 |
(items, Event.idsupitem == items.c.idsupitem), |
|
230 | 250 |
).filter( |
231 | 251 |
# On masque les événements avec l'état OK |
232 | 252 |
# et traités (status == u'AAClosed'). |
... | ... | |
236 | 256 |
)) |
237 | 257 |
).filter(CorrEvent.idcorrevent == idcorrevent |
238 | 258 |
).one() |
259 |
|
|
260 |
|
|
239 | 261 |
# except: |
240 | 262 |
# # XXX Raise some HTTP error. |
241 | 263 |
# return None |
... | ... | |
253 | 275 |
# Rappel: |
254 | 276 |
# event[0] = priorité de l'alerte corrélée. |
255 | 277 |
# event[1] = alerte brute. |
278 |
if event[3]: |
|
279 |
service = urllib.quote(event[3]) |
|
280 |
else: |
|
281 |
service = None |
|
256 | 282 |
eventdetails[edname] = edlink[1] % { |
257 | 283 |
'idcorrevent': idcorrevent, |
258 |
'host': urllib.quote(event[1].supitem.host.name),
|
|
259 |
'service': urllib.quote(event[1].supitem.servicename),
|
|
284 |
'host': urllib.quote(event[2]),
|
|
285 |
'service': service,
|
|
260 | 286 |
'message': urllib.quote(event[1].message), |
261 | 287 |
} |
262 | 288 |
|
... | ... | |
268 | 294 |
peak_state = StateName.value_to_statename( |
269 | 295 |
event[1].peak_state), |
270 | 296 |
idcorrevent = idcorrevent, |
271 |
host = event[1].supitem.host.name,
|
|
272 |
service = event[1].supitem.servicename,
|
|
297 |
host = event[2],
|
|
298 |
service = event[3],
|
|
273 | 299 |
eventdetails = eventdetails, |
274 | 300 |
) |
275 | 301 |
|
... | ... | |
324 | 350 |
refresh_times=config['vigiboard_refresh_times'], |
325 | 351 |
) |
326 | 352 |
|
327 |
@validate(validators={'host': validators.NotEmpty(), |
|
328 |
'service': validators.NotEmpty()}, error_handler=process_form_errors) |
|
353 |
@validate( |
|
354 |
validators={ |
|
355 |
'host': validators.NotEmpty(), |
|
356 |
# 'service': validators.NotEmpty() |
|
357 |
}, |
|
358 |
error_handler=process_form_errors) |
|
329 | 359 |
@expose('vigiboard.html') |
330 | 360 |
@require(Any(not_anonymous(), msg=l_("You need to be authenticated"))) |
331 |
def host_service(self, host, service): |
|
361 |
def host_service(self, host, service=None):
|
|
332 | 362 |
|
333 | 363 |
""" |
334 | 364 |
Affichage de l'historique de l'ensemble des événements correspondant |
... | ... | |
339 | 369 |
@param service: Nom du service souhaité |
340 | 370 |
""" |
341 | 371 |
|
372 |
idsupitem = SupItem.get_supitem(host, service) |
|
373 |
|
|
342 | 374 |
username = request.environ['repoze.who.identity']['repoze.who.userid'] |
343 | 375 |
events = VigiboardRequest(User.by_user_name(username)) |
344 |
events.add_join((ServiceLowLevel, ServiceLowLevel.idservice == \ |
|
345 |
Event.idsupitem)) |
|
346 |
events.add_join((Host, ServiceLowLevel.idhost == Host.idhost)) |
|
347 |
events.add_filter(Host.name == host, |
|
348 |
ServiceLowLevel.servicename == service) |
|
376 |
events.add_filter(events.items.c.idsupitem == idsupitem) |
|
349 | 377 |
|
350 | 378 |
# XXX On devrait avoir une autre API que ça !!! |
351 | 379 |
# Supprime le filtre qui empêche d'obtenir des événements fermés |
352 | 380 |
# (ie: ayant l'état Nagios 'OK' et le statut 'AAClosed'). |
353 |
if len(events.filter) > 2:
|
|
354 |
del events.filter[2]
|
|
381 |
if len(events.filter) > 0:
|
|
382 |
del events.filter[0]
|
|
355 | 383 |
|
356 | 384 |
# Vérification qu'il y a au moins 1 événement qui correspond |
357 | 385 |
if events.num_rows() == 0 : |
... | ... | |
419 | 447 |
|
420 | 448 |
# Si des changements sont survenus depuis que la |
421 | 449 |
# page est affichée, on en informe l'utilisateur. |
422 |
if datetime.fromtimestamp(float(krgv['last_modification'])) \ |
|
423 |
< get_last_modification_timestamp(ids): |
|
424 |
flash(_('Changes have occurred since the page was last displayed, ' |
|
450 |
last_modification = get_last_modification_timestamp(ids, None) |
|
451 |
if last_modification and datetime.fromtimestamp(\ |
|
452 |
float(krgv['last_modification'])) < last_modification: |
|
453 |
flash(_('Changes have occurred since the page was displayed, ' |
|
425 | 454 |
'your changes HAVE NOT been saved.'), 'warning') |
455 |
print "\n\n\n\n\n" |
|
456 |
print datetime.fromtimestamp(float(krgv['last_modification'])) |
|
457 |
print get_last_modification_timestamp(ids) |
|
458 |
print "\n\n\n\n\n" |
|
459 |
|
|
426 | 460 |
raise redirect(request.environ.get('HTTP_REFERER', url('/'))) |
427 | 461 |
|
428 | 462 |
# Si l'utilisateur édite plusieurs événements à la fois, |
... | ... | |
538 | 572 |
session.save() |
539 | 573 |
return dict() |
540 | 574 |
|
541 |
def get_last_modification_timestamp(event_id_list): |
|
575 |
def get_last_modification_timestamp(event_id_list, |
|
576 |
value_if_none=datetime.now()): |
|
542 | 577 |
""" |
543 | 578 |
Récupère le timestamp de la dernière modification |
544 | 579 |
opérée sur l'un des événements dont l'identifiant |
... | ... | |
548 | 583 |
func.max(EventHistory.timestamp), |
549 | 584 |
).filter(EventHistory.idevent.in_(event_id_list) |
550 | 585 |
).scalar() |
551 |
|
|
552 | 586 |
if not last_modification_timestamp: |
553 |
last_modification_timestamp = datetime.now()
|
|
554 |
# On élimine la fraction (microsecondes) de l'objet datetime.
|
|
555 |
# XXX Dans l'idéal, on devrait gérer les microsecondes.
|
|
556 |
# Problème: les erreurs d'arrondis empêchent certaines modifications.
|
|
587 |
if not value_if_none:
|
|
588 |
return None
|
|
589 |
else:
|
|
590 |
last_modification_timestamp = value_if_none
|
|
557 | 591 |
return datetime.fromtimestamp(mktime( |
558 | 592 |
last_modification_timestamp.timetuple())) |
559 |
|
vigiboard/controllers/vigiboardrequest.py | ||
---|---|---|
11 | 11 |
from tg import url, config, tmpl_context |
12 | 12 |
from vigiboard.model import DBSession |
13 | 13 |
from sqlalchemy import not_, and_, asc, desc, sql |
14 |
from sqlalchemy.sql.expression import or_ |
|
14 |
from sqlalchemy.sql.expression import or_, null as expr_null, union
|
|
15 | 15 |
from sqlalchemy.orm import aliased |
16 | 16 |
from vigiboard.widgets.edit_event import EditEventForm |
17 | 17 |
from vigiboard.widgets.search_form import SearchForm |
... | ... | |
54 | 54 |
self.lang = lang |
55 | 55 |
self.generaterq = False |
56 | 56 |
|
57 |
associated_host = aliased(Host) |
|
58 |
lls_query = DBSession.query(ServiceLowLevel.idservice.label("idsupitem"), |
|
59 |
ServiceLowLevel.servicename, |
|
60 |
associated_host.name.label("hostname") |
|
61 |
).join((associated_host, |
|
62 |
associated_host.idhost == ServiceLowLevel.idhost), |
|
63 |
) |
|
57 |
lls_query = DBSession.query( |
|
58 |
ServiceLowLevel.idservice.label("idsupitem"), |
|
59 |
ServiceLowLevel.servicename.label("servicename"), |
|
60 |
Host.name.label("hostname"), |
|
61 |
SERVICE_GROUP_TABLE.c.idgroup.label("idservicegroup"), |
|
62 |
HOST_GROUP_TABLE.c.idgroup.label("idhostgroup"), |
|
63 |
).join( |
|
64 |
(Host, Host.idhost == ServiceLowLevel.idhost), |
|
65 |
).outerjoin( |
|
66 |
(HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == ServiceLowLevel.idservice), |
|
67 |
(SERVICE_GROUP_TABLE, SERVICE_GROUP_TABLE.c.idservice == ServiceLowLevel.idservice), |
|
68 |
).filter( |
|
69 |
or_( |
|
70 |
HOST_GROUP_TABLE.c.idgroup.in_(self.user_groups), |
|
71 |
SERVICE_GROUP_TABLE.c.idgroup.in_(self.user_groups), |
|
72 |
), |
|
73 |
) |
|
64 | 74 |
|
65 |
host_query = DBSession.query(Host.idhost.label("idsupitem"), |
|
66 |
"NULL", |
|
67 |
Host.name.label("hostname")) |
|
68 |
|
|
69 |
items = lls_query.union(host_query).subquery() |
|
75 |
host_query = DBSession.query( |
|
76 |
Host.idhost.label("idsupitem"), |
|
77 |
expr_null().label("servicename"), |
|
78 |
Host.name.label("hostname"), |
|
79 |
expr_null().label("idservicegroup"), |
|
80 |
HOST_GROUP_TABLE.c.idgroup.label('idhostgroup'), |
|
81 |
).join((HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == Host.idhost) |
|
82 |
).filter(HOST_GROUP_TABLE.c.idgroup.label('idhostgroup').in_(self.user_groups), |
|
83 |
) |
|
84 |
|
|
85 |
# On est obligés d'utiliser sqlalchemy.sql.expression.union |
|
86 |
# pour indiquer à SQLAlchemy de NE PAS regrouper les tables |
|
87 |
# dans la requête principale, sans quoi les résultats sont |
|
88 |
# incorrects. |
|
89 |
self.items = union(lls_query, host_query, correlate=False).alias() |
|
70 | 90 |
|
71 | 91 |
self.table = [ |
72 | 92 |
CorrEvent, |
73 | 93 |
sql.func.count(CorrEvent.idcorrevent), |
74 |
items.hostname,
|
|
75 |
items.servicename,
|
|
94 |
self.items.c.hostname,
|
|
95 |
self.items.c.servicename,
|
|
76 | 96 |
] |
77 | 97 |
|
78 |
# self.join = [ |
|
79 |
# (Event, CorrEvent.idcause == Event.idevent), |
|
80 |
# (ServiceLowLevel, Event.idsupitem == ServiceLowLevel.idservice), |
|
81 |
# (Host, Host.idhost == ServiceLowLevel.idhost), |
|
82 |
# (StateName, StateName.idstatename == Event.current_state), |
|
83 |
# ] |
|
84 |
# |
|
85 |
# self.outerjoin = [ |
|
86 |
# (HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == Host.idhost), |
|
87 |
# (SERVICE_GROUP_TABLE, SERVICE_GROUP_TABLE.c.idservice == \ |
|
88 |
# ServiceLowLevel.idservice), |
|
89 |
# ] |
|
90 |
|
|
91 | 98 |
self.join = [ |
92 | 99 |
(Event, CorrEvent.idcause == Event.idevent), |
93 |
(items, Event.idsupitem == items.c.idsupitem),
|
|
100 |
(self.items, Event.idsupitem == self.items.c.idsupitem),
|
|
94 | 101 |
(StateName, StateName.idstatename == Event.current_state), |
95 | 102 |
] |
96 |
|
|
97 |
self.outerjoin = [ |
|
98 |
(HOST_GROUP_TABLE, HOST_GROUP_TABLE.c.idhost == items.c.idsupitem), |
|
99 |
(SERVICE_GROUP_TABLE, SERVICE_GROUP_TABLE.c.idservice == \ |
|
100 |
items.c.idsupitem), |
|
101 |
] |
|
103 |
|
|
104 |
self.outerjoin = [] |
|
102 | 105 |
|
103 | 106 |
self.filter = [ |
104 |
or_( |
|
105 |
HOST_GROUP_TABLE.c.idgroup.in_(self.user_groups), |
|
106 |
SERVICE_GROUP_TABLE.c.idgroup.in_(self.user_groups), |
|
107 |
), |
|
108 |
|
|
109 |
# On masque les événements avec l'état OK |
|
110 |
# et traités (status == u'AAClosed'). |
|
111 |
not_(and_( |
|
112 |
StateName.statename == u'OK', |
|
113 |
CorrEvent.status == u'AAClosed' |
|
114 |
)), |
|
115 |
CorrEvent.timestamp_active != None, |
|
116 |
] |
|
107 |
# On masque les événements avec l'état OK |
|
108 |
# et traités (status == u'AAClosed'). |
|
109 |
not_(and_( |
|
110 |
StateName.statename == u'OK', |
|
111 |
CorrEvent.status == u'AAClosed' |
|
112 |
)), |
|
113 |
CorrEvent.timestamp_active != None, |
|
114 |
] |
|
117 | 115 |
|
118 | 116 |
# Permet de définir le sens de tri pour la priorité. |
119 | 117 |
if config['vigiboard_priority_order'] == 'asc': |
... | ... | |
122 | 120 |
priority_order = desc(CorrEvent.priority) |
123 | 121 |
|
124 | 122 |
self.orderby = [ |
125 |
desc(CorrEvent.status), # None, Acknowledged, AAClosed
|
|
126 |
priority_order, # Priorité ITIL (entier).
|
|
127 |
desc(StateName.order), # Etat courant (entier).
|
|
128 |
desc(Event.timestamp),
|
|
129 |
asc(items.c.hostname),
|
|
130 |
]
|
|
123 |
desc(CorrEvent.status), # None, Acknowledged, AAClosed
|
|
124 |
priority_order, # Priorité ITIL (entier). |
|
125 |
desc(StateName.order), # Etat courant (entier). |
|
126 |
desc(Event.timestamp), |
|
127 |
asc(self.items.c.hostname),
|
|
128 |
] |
|
131 | 129 |
|
132 | 130 |
self.groupby = [ |
133 |
CorrEvent.idcorrevent, |
|
134 | 131 |
CorrEvent, |
135 |
items.c.hostname, |
|
132 |
self.items.c.hostname, |
|
133 |
self.items.c.servicename, |
|
136 | 134 |
StateName.order, |
137 | 135 |
Event.timestamp, |
138 | 136 |
] |
... | ... | |
193 | 191 |
self.req = self.req.group_by(i) |
194 | 192 |
for i in self.orderby: |
195 | 193 |
self.req = self.req.order_by(i) |
196 |
# raise ValueError, self.req.statement |
|
197 | 194 |
|
198 | 195 |
def num_rows(self): |
199 | 196 |
|
... | ... | |
391 | 388 |
event = req |
392 | 389 |
else: |
393 | 390 |
event = req[0] |
391 |
hostname = req[2] |
|
392 |
servicename = req[3] |
|
394 | 393 |
ids.append(event.idcause) |
395 | 394 |
|
396 | 395 |
# La liste pour l'événement actuel comporte dans l'ordre : |
... | ... | |
407 | 406 |
|
408 | 407 |
events.append([ |
409 | 408 |
event, |
409 |
hostname, |
|
410 |
servicename, |
|
410 | 411 |
{'class': class_tr[i % 2]}, |
411 | 412 |
{'class': StateName.value_to_statename( |
412 | 413 |
cause.initial_state) + |
Also available in: Unified diff