Revision d5a41c9b
Inhibition des alertes (#1187).
Refs: #1187
Change-Id: I87a9c86eb2ecd344b31e092d9dbd645d79ea4cba
Reviewed-on: https://vigilo-dev.si.c-s.fr/review/1293
Tested-by: Build system <qa@vigilo-dev.si.c-s.fr>
Reviewed-by: Francois POIROTTE <francois.poirotte@c-s.fr>
doc/util.rst | ||
---|---|---|
334 | 334 |
|
335 | 335 |
|
336 | 336 |
|
337 |
Inhibition des alertes |
|
338 |
------------------------------------ |
|
339 |
Cette fonctionnalité permet d'empêcher l'apparition de nouvelles alertes dans |
|
340 |
VigiBoard pour un hôte ou un service donné. La page listant les règles |
|
341 |
d'inhibition (aussi appelées règles de mise en silence) actives est accessible |
|
342 |
en cliquant sur l'icône ci-dessous située en haut à droite de l'interface : |
|
343 |
|
|
344 |
.. figure:: img/silence_rules.png |
|
345 |
|
|
346 |
Les règles sont triées par défaut par ordre décroissant de dernière mise à jour, |
|
347 |
comme on peut le voir sur la capture ci-dessous : |
|
348 |
|
|
349 |
.. Capture à ajouter |
|
350 |
|
|
351 |
Depuis cette page, il est alors possible d'éditer ou de supprimer une règle |
|
352 |
existante en cliquant sur l'une des deux icônes située en début de ligne : |
|
353 |
|
|
354 |
.. figure:: img/silence_update_delete.png |
|
355 |
|
|
356 |
L'utilisateur est également en mesure d'ajouter une nouvelle règle en cliquant |
|
357 |
sur le bouton prévu à cet effet situé juste au-dessus du tableau : |
|
358 |
|
|
359 |
.. figure:: img/silence_add.png |
|
360 |
|
|
361 |
.. note:: |
|
362 |
Les alertes déjà traitées (c'est à dire soit déjà ignorées, soit déjà |
|
363 |
affichées dans VigiBoard) ne sont pas impactées par les modifications faites |
|
364 |
sur les règles (ie. aucun traitement n'est réalisé a posteriori pour générer |
|
365 |
des alertes ou pour détruire des alertes déjà présentes). |
|
366 |
De même, ce filtrage n'impacte que la production d'alertes, il ne concerne |
|
367 |
pas l'état des hôtes/services (donc l'élément peut être ``CRITICAL`` dans |
|
368 |
VigiMap mais ne pas avoir d'alarme correspondante dans VigiBoard). |
|
369 |
|
|
370 |
|
|
371 |
|
|
337 | 372 |
Annexes |
338 | 373 |
======= |
339 | 374 |
|
test.ini | ||
---|---|---|
36 | 36 |
[app:unlimited_maps] |
37 | 37 |
use = main_without_authn |
38 | 38 |
max_maps = -2 |
39 |
|
|
40 |
[app:pagination] |
|
41 |
use = main |
|
42 |
vigiboard_items_per_page = 1 |
vigiboard/controllers/root.py | ||
---|---|---|
58 | 58 |
|
59 | 59 |
from vigiboard.controllers.vigiboardrequest import VigiboardRequest |
60 | 60 |
from vigiboard.controllers.feeds import FeedsController |
61 |
from vigiboard.controllers.silence import SilenceController |
|
61 | 62 |
|
62 | 63 |
from vigiboard.lib import export_csv, dateformat |
63 | 64 |
from vigiboard.widgets.edit_event import edit_event_status_options, \ |
... | ... | |
87 | 88 |
not_anonymous(l_('You need to be authenticated'))) |
88 | 89 |
api = ApiRootController() |
89 | 90 |
feeds = FeedsController() |
91 |
silence = SilenceController() |
|
90 | 92 |
custom = CustomController() |
91 | 93 |
|
92 | 94 |
# Prédicat pour la restriction de l'accès aux interfaces. |
vigiboard/controllers/silence.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# vim:set expandtab tabstop=4 shiftwidth=4: |
|
3 |
############################################################################### |
|
4 |
# |
|
5 |
# Copyright (C) 2007-2013 CS-SI |
|
6 |
# |
|
7 |
# This program is free software; you can redistribute it and/or modify |
|
8 |
# it under the terms of the GNU General Public License version 2 as |
|
9 |
# published by the Free Software Foundation. |
|
10 |
# |
|
11 |
# This program is distributed in the hope that it will be useful, |
|
12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
# GNU General Public License for more details. |
|
15 |
# |
|
16 |
# You should have received a copy of the GNU General Public License |
|
17 |
# along with this program; if not, write to the Free Software |
|
18 |
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 |
############################################################################### |
|
20 |
|
|
21 |
"""Gère la planification des mises en silence.""" |
|
22 |
|
|
23 |
#import time |
|
24 |
from datetime import datetime |
|
25 |
|
|
26 |
from tg import expose, validate, require, flash, tmpl_context, \ |
|
27 |
request, config, redirect |
|
28 |
from pylons.i18n import lazy_ugettext as l_, ugettext as _ |
|
29 |
#from tg.i18n import get_lang |
|
30 |
|
|
31 |
#from tw.forms import CalendarDateTimePicker |
|
32 |
from webhelpers import paginate |
|
33 |
from tw.forms import validators |
|
34 |
|
|
35 |
from vigilo.turbogears.helpers import get_current_user |
|
36 |
from repoze.what.predicates import Any, All, in_group, \ |
|
37 |
has_permission, not_anonymous |
|
38 |
from formencode import schema |
|
39 |
from formencode.compound import All as All_ |
|
40 |
from formencode.foreach import ForEach |
|
41 |
|
|
42 |
from sqlalchemy.exc import InvalidRequestError, IntegrityError |
|
43 |
from sqlalchemy.sql.expression import asc, desc |
|
44 |
|
|
45 |
from vigilo.turbogears.controllers import BaseController |
|
46 |
from vigilo.models.session import DBSession |
|
47 |
|
|
48 |
from vigilo.models.tables import SupItem, Host, LowLevelService, \ |
|
49 |
HighLevelService, StateName, Silence, UserSupItem |
|
50 |
from vigilo.models.tables.secondary_tables import SILENCE_STATE_TABLE |
|
51 |
|
|
52 |
from vigilo.models.utils import group_concat |
|
53 |
|
|
54 |
import logging |
|
55 |
|
|
56 |
LOGGER = logging.getLogger(__name__) |
|
57 |
|
|
58 |
__all__ = ['SilenceController'] |
|
59 |
|
|
60 |
# pylint: disable-msg=R0201 |
|
61 |
class SilenceController(BaseController): |
|
62 |
""" |
|
63 |
Contrôleur gérant la planification des mises en silence. |
|
64 |
""" |
|
65 |
|
|
66 |
# Prédicat pour la restriction de l'accès aux interfaces. |
|
67 |
# L'utilisateur doit avoir la permission "vigiboard-silence" |
|
68 |
# ou appartenir au groupe "managers" pour accéder à VigiBoard. |
|
69 |
access_restriction = All( |
|
70 |
not_anonymous(msg=l_("You need to be authenticated")), |
|
71 |
Any(in_group('managers'), |
|
72 |
has_permission('vigiboard-silence'), |
|
73 |
msg=l_("Insufficient privileges for this action")) |
|
74 |
) |
|
75 |
|
|
76 |
def handle_error_message(self, message, redirection_url='./'): |
|
77 |
""" |
|
78 |
Affiche le message dans l'IHM, l'enregistre dans les logs |
|
79 |
et renvoie le navigateur vers l'URL de redirection. |
|
80 |
|
|
81 |
@param message: message d'erreur à afficher |
|
82 |
@type message: C{str} |
|
83 |
@param redirection_url: (optionnel) URL de redirection |
|
84 |
@type redirection_url: C{str} |
|
85 |
""" |
|
86 |
LOGGER.error(message) |
|
87 |
flash(message, 'error') |
|
88 |
redirect(redirection_url) |
|
89 |
|
|
90 |
def process_form_errors(self, *argv, **kwargv): |
|
91 |
""" |
|
92 |
Gestion des erreurs de validation : on affiche les erreurs |
|
93 |
puis on redirige vers la dernière page accédée. |
|
94 |
""" |
|
95 |
for k in tmpl_context.form_errors: |
|
96 |
flash("'%s': %s" % (k, tmpl_context.form_errors[k]), 'error') |
|
97 |
redirect(request.environ.get('HTTP_REFERER', '/')) |
|
98 |
|
|
99 |
def query_silences(self): |
|
100 |
""" |
|
101 |
Retourne une requête SQLAlchemy interrogeant |
|
102 |
la table des mises en silence |
|
103 |
""" |
|
104 |
|
|
105 |
# Si l'utilisateur fait partie du groupe 'managers', on récupère la |
|
106 |
# liste de tous les supitems de la base de données |
|
107 |
if in_group('managers').is_met(request.environ): |
|
108 |
lls_query = DBSession.query( |
|
109 |
LowLevelService.idservice.label('idsupitem'), |
|
110 |
LowLevelService.servicename.label("servicename"), |
|
111 |
Host.name.label('hostname') |
|
112 |
).join((Host, Host.idhost == LowLevelService.idhost)) |
|
113 |
|
|
114 |
host_query = DBSession.query( |
|
115 |
Host.idhost.label('idsupitem'), |
|
116 |
"NULL", |
|
117 |
Host.name.label('hostname') |
|
118 |
) |
|
119 |
|
|
120 |
supitems = lls_query.union(host_query).subquery() |
|
121 |
|
|
122 |
# Sinon on ne récupère que les supitems auxquels l'utilisateurs a accès |
|
123 |
else: |
|
124 |
user_name = request.identity['repoze.who.userid'] |
|
125 |
supitems = DBSession.query( |
|
126 |
UserSupItem.idsupitem.label('idsupitem'), |
|
127 |
UserSupItem.servicename.label("servicename"), |
|
128 |
UserSupItem.hostname.label('hostname') |
|
129 |
).filter( |
|
130 |
UserSupItem.username == user_name |
|
131 |
).distinct().subquery() |
|
132 |
|
|
133 |
# On interroge la base pour avoir la liste des règles de mise en silence |
|
134 |
# correspondant à ces supitems. |
|
135 |
states = DBSession.query( |
|
136 |
SILENCE_STATE_TABLE.c.idsilence, |
|
137 |
StateName.statename |
|
138 |
).join((StateName, |
|
139 |
StateName.idstatename == SILENCE_STATE_TABLE.c.idstate) |
|
140 |
).order_by(StateName.statename |
|
141 |
).subquery() |
|
142 |
states = DBSession.query( |
|
143 |
states.c.idsilence, |
|
144 |
group_concat(states.c.statename, ', ').label('states'), |
|
145 |
).group_by(states.c.idsilence |
|
146 |
).subquery() |
|
147 |
silences = DBSession.query( |
|
148 |
Silence, |
|
149 |
supitems.c.hostname, |
|
150 |
supitems.c.servicename, |
|
151 |
states.c.states |
|
152 |
).join((supitems, supitems.c.idsupitem == Silence.idsupitem) |
|
153 |
).join((states, states.c.idsilence == Silence.idsilence)) |
|
154 |
|
|
155 |
return silences |
|
156 |
|
|
157 |
def check_silence_rule_existence(self, idsupitem): |
|
158 |
""" |
|
159 |
S'assure qu'aucune règle de mise en silence n'existe dans la base de |
|
160 |
données pour le supitem considéré, et affiche un message d'erreur dans |
|
161 |
le cas contraire. |
|
162 |
|
|
163 |
@param idsupitem: Identifiant du supitem. |
|
164 |
@type idsupitem: C{int} |
|
165 |
""" |
|
166 |
silence = DBSession.query(Silence |
|
167 |
).filter(Silence.idsupitem == idsupitem |
|
168 |
).first() |
|
169 |
if not silence: |
|
170 |
return |
|
171 |
if isinstance(silence.supitem, LowLevelService): |
|
172 |
msg = _("Another rule already exists for service '%s' " \ |
|
173 |
"on host '%s'.") % (silence.supitem.servicename, |
|
174 |
silence.supitem.host.name) |
|
175 |
else: |
|
176 |
msg = _("Another rule already exists for host '%s'.") % ( |
|
177 |
silence.supitem.name) |
|
178 |
self.handle_error_message(msg) |
|
179 |
|
|
180 |
class IndexSchema(schema.Schema): |
|
181 |
"""Schéma de validation de la méthode index.""" |
|
182 |
# Si on ne passe pas le paramètre "page" ou qu'on passe une valeur |
|
183 |
# invalide ou pas de valeur du tout, alors on affiche la 1ère page. |
|
184 |
page = validators.Int(min=1, if_missing=1, |
|
185 |
if_invalid=1, not_empty=True) |
|
186 |
sort = validators.OneOf( |
|
187 |
['hostname', 'servicename', 'lastmodification', |
|
188 |
'author', 'comment', 'states'], |
|
189 |
if_missing='lastmodification', if_invalid='lastmodification') |
|
190 |
order = validators.OneOf(['desc', 'asc'], |
|
191 |
if_missing='desc', if_invalid='desc') |
|
192 |
|
|
193 |
@validate( |
|
194 |
validators=IndexSchema(), |
|
195 |
error_handler = process_form_errors) |
|
196 |
@expose('silence.html') |
|
197 |
@require(access_restriction) |
|
198 |
def index(self, page=1, sort=None, order=None): |
|
199 |
""" |
|
200 |
Affiche la liste des règles de mise en silence enregistrées dans |
|
201 |
la BDD, que l'utilisateur pourra ensuite éditer ou supprimer. |
|
202 |
|
|
203 |
@param sort: (optionnel) Critère de tri de la liste des |
|
204 |
règles de mise en silence enregistrées. |
|
205 |
@type sort: C{str} |
|
206 |
@param order: (optionnel) Ordre de tri. |
|
207 |
@type order: C{str} |
|
208 |
""" |
|
209 |
|
|
210 |
# # On récupère la langue de l'utilisateur |
|
211 |
# lang = get_lang() |
|
212 |
# if not lang: |
|
213 |
# lang = ['fr'] |
|
214 |
# lang = lang[0] |
|
215 |
|
|
216 |
# On récupère tous les enregistrements de la table |
|
217 |
# silence, qu'ils concernent des hôtes, des services |
|
218 |
# de bas niveau, ou bien des services de haut niveau. |
|
219 |
silences = self.query_silences() |
|
220 |
|
|
221 |
# On trie ces enregistrements selon le critère choisi |
|
222 |
# par l'utilisateur (par défaut, la date d'ajout). |
|
223 |
sort_keys = { |
|
224 |
'hostname': 'hostname', |
|
225 |
'servicename': 'servicename', |
|
226 |
'lastmodification': Silence.lastmodification, |
|
227 |
'author': Silence.author, |
|
228 |
'comment': Silence.comment, |
|
229 |
# 'start': Silence.start, |
|
230 |
# 'end': Silence.end, |
|
231 |
'states': 'states', |
|
232 |
} |
|
233 |
if sort in sort_keys.keys(): |
|
234 |
# Tri dans l'ordre croissant |
|
235 |
if order != 'desc': |
|
236 |
silences = silences.order_by(asc(sort_keys[sort])) |
|
237 |
# Tri dans l'ordre décroissant |
|
238 |
else: |
|
239 |
silences = silences.order_by(desc(sort_keys[sort])) |
|
240 |
|
|
241 |
# On calcule la pagination |
|
242 |
page = paginate.Page(silences, page=page, |
|
243 |
items_per_page=int(config['vigiboard_items_per_page'])) |
|
244 |
|
|
245 |
# # On initialise les widgets des calendriers |
|
246 |
# # utilisés dans le formulaire de mise en silence. |
|
247 |
# start_calendar = CalendarDateTimePicker('start', |
|
248 |
# button_text = l_("Choose a date"), |
|
249 |
# date_format = '%Y-%m-%d %H:%M', |
|
250 |
# calendar_lang = lang) |
|
251 |
# end_calendar = CalendarDateTimePicker('end', |
|
252 |
# button_text = l_("Choose a date"), |
|
253 |
# date_format = '%Y-%m-%d %H:%M', |
|
254 |
# calendar_lang = lang) |
|
255 |
|
|
256 |
# Traduction du nom des colonnes |
|
257 |
columns = [ |
|
258 |
('hostname', l_('Host')), |
|
259 |
('servicename', l_('Service')), |
|
260 |
('states', l_('States')), |
|
261 |
('lastmodification', l_('Last modification')), |
|
262 |
('author', l_('Author')), |
|
263 |
('comment', l_('Comment')) |
|
264 |
] |
|
265 |
|
|
266 |
return dict( |
|
267 |
page=page, |
|
268 |
sort=sort, |
|
269 |
order=order, |
|
270 |
# start_calendar=start_calendar, |
|
271 |
# end_calendar=end_calendar, |
|
272 |
columns=columns |
|
273 |
) |
|
274 |
|
|
275 |
@expose('silence_form.html') |
|
276 |
@require(access_restriction) |
|
277 |
def add(self): |
|
278 |
""" |
|
279 |
Affiche un formulaire d'ajout d'une règle de mise en silence. |
|
280 |
""" |
|
281 |
return dict( |
|
282 |
id=None, |
|
283 |
hostname=None, |
|
284 |
servicename=None, |
|
285 |
states=None, |
|
286 |
comment=None, |
|
287 |
# start_calendar=start_calendar, |
|
288 |
# end_calendar=end_calendar, |
|
289 |
) |
|
290 |
|
|
291 |
class UpdateSchema(schema.Schema): |
|
292 |
"""Schéma de validation de la méthode update.""" |
|
293 |
id = validators.Int(min=1, not_empty=True) |
|
294 |
|
|
295 |
@validate( |
|
296 |
validators=UpdateSchema(), |
|
297 |
error_handler = process_form_errors) |
|
298 |
@expose('silence_form.html') |
|
299 |
@require(access_restriction) |
|
300 |
def update(self, id): |
|
301 |
""" |
|
302 |
Affiche un formulaire de mise à jour d'une règle de mise en silence. |
|
303 |
|
|
304 |
@param id: Identifiant de la règle. |
|
305 |
@type id: C{int} |
|
306 |
""" |
|
307 |
|
|
308 |
# On s'assure que la règle existe bien dans la base |
|
309 |
try: |
|
310 |
silence = DBSession.query(Silence |
|
311 |
).filter(Silence.idsilence == id).one() |
|
312 |
except InvalidRequestError, e: |
|
313 |
msg = _('An exception has been raised while ' \ |
|
314 |
'querying the database: %s') % str(e) |
|
315 |
self.handle_error_message(msg) |
|
316 |
if not silence: |
|
317 |
msg = _("Silence rule #%s does not exist.") % id |
|
318 |
self.handle_error_message(msg) |
|
319 |
|
|
320 |
# On s'assure que l'utilisateur dispose bien des permissions sur le |
|
321 |
# supitem considéré |
|
322 |
user = get_current_user() |
|
323 |
if not silence.supitem.is_allowed_for(user): |
|
324 |
msg = _("Silence rule #%s does not exist.") % id |
|
325 |
self.handle_error_message(msg) |
|
326 |
|
|
327 |
if hasattr(silence.supitem, 'servicename'): |
|
328 |
hostname = silence.supitem.host.name |
|
329 |
servicename = silence.supitem.servicename |
|
330 |
else: |
|
331 |
hostname = silence.supitem.name |
|
332 |
servicename = None |
|
333 |
|
|
334 |
return dict( |
|
335 |
id=id, |
|
336 |
hostname=hostname, |
|
337 |
servicename=servicename, |
|
338 |
states=[s.statename for s in silence.states], |
|
339 |
comment=silence.comment, |
|
340 |
# start_calendar=start_calendar, |
|
341 |
# end_calendar=end_calendar, |
|
342 |
) |
|
343 |
|
|
344 |
class CreateOrModifySchema(schema.Schema): |
|
345 |
"""Schéma de validation de la méthode create_or_modify.""" |
|
346 |
states = All_( |
|
347 |
validators.Set(use_set=True), |
|
348 |
validators.OneOf(["WARNING", "CRITICAL", "DOWN", "UNKNOWN"], |
|
349 |
testValueList=True, hideList=True, not_empty=True) |
|
350 |
) |
|
351 |
host = validators.String(not_empty=True) |
|
352 |
service = validators.String() |
|
353 |
comment = validators.String() |
|
354 |
idsilence = validators.Int(min=1, if_missing=None, |
|
355 |
if_invalid=None, not_empty=False) |
|
356 |
|
|
357 |
@validate( |
|
358 |
validators=CreateOrModifySchema(), |
|
359 |
error_handler = process_form_errors) |
|
360 |
@expose() |
|
361 |
@require(access_restriction) |
|
362 |
def create_or_modify( |
|
363 |
self, |
|
364 |
states, |
|
365 |
host, |
|
366 |
service=None, |
|
367 |
# start=time.time(), |
|
368 |
# end=time.time(), |
|
369 |
comment=None, |
|
370 |
idsilence=None): |
|
371 |
""" |
|
372 |
Ajoute une règle de mise en silence d'un hôte/service, |
|
373 |
ou en modifie une déjà existante. |
|
374 |
|
|
375 |
@param states: (optionnel) Liste des états concernés par la règle. |
|
376 |
@type states: C{list} of C{unicode} |
|
377 |
@param host: Nom de l'hôte sur lequel porte la règle. |
|
378 |
@type host: C{unicode} |
|
379 |
@param service: (optionnel) Nom du service sur lequel |
|
380 |
porte la règle. |
|
381 |
@type service: C{unicode} |
|
382 |
# @param start: Début de la mise en silence planifiée. |
|
383 |
# @type start: C{str} |
|
384 |
# @param end: Fin de la mise en silence planifiée. |
|
385 |
# @type end: C{str} |
|
386 |
@param comment: (optionnel) Commentaire accompagnant la règle. |
|
387 |
@type comment: C{unicode} |
|
388 |
@param idsilence: (optionnel) Identifiant de la règle dans le cas d'une |
|
389 |
mise à jour. |
|
390 |
@type idsilence: C{int} |
|
391 |
""" |
|
392 |
|
|
393 |
# TODO: Faire ce traitement dans le schéma de validation |
|
394 |
if not states: |
|
395 |
msg = _('No state specified for the silence rule.') |
|
396 |
self.handle_error_message(msg) |
|
397 |
states = list(states) |
|
398 |
|
|
399 |
# On récupère le nom et l'IP de l'utilisateur. |
|
400 |
user = get_current_user() |
|
401 |
user_name = user.user_name |
|
402 |
user_ip = request.remote_addr |
|
403 |
|
|
404 |
# On récupère l'identifiant de l'item (hôte |
|
405 |
# ou service) concerné par la mise en silence. |
|
406 |
idsupitem = SupItem.get_supitem(host, service) |
|
407 |
if idsupitem: |
|
408 |
try: |
|
409 |
supitem = DBSession.query(SupItem |
|
410 |
).filter(SupItem.idsupitem == idsupitem).one() |
|
411 |
except InvalidRequestError, e: |
|
412 |
msg = _('An exception has been raised while ' \ |
|
413 |
'querying the database: %s') % str(e) |
|
414 |
self.handle_error_message(msg) |
|
415 |
if not idsupitem or not supitem.is_allowed_for(user): |
|
416 |
if not service: |
|
417 |
msg = _("Host '%s' does not exist.") % host |
|
418 |
self.handle_error_message(msg) |
|
419 |
else: |
|
420 |
msg = _("Service '%s' does not exist for host '%s'." |
|
421 |
) % (service, host) |
|
422 |
self.handle_error_message(msg) |
|
423 |
|
|
424 |
# On distingue mise à jour et création : |
|
425 |
|
|
426 |
# 1. Dans le cas d'une mise à jour : |
|
427 |
if idsilence: |
|
428 |
|
|
429 |
# - On s'assure que la règle existe bien dans la base |
|
430 |
try: |
|
431 |
silence = DBSession.query(Silence |
|
432 |
).filter(Silence.idsilence == idsilence).one() |
|
433 |
except InvalidRequestError, e: |
|
434 |
msg = _('An exception has been raised while ' \ |
|
435 |
'querying the database: %s') % str(e) |
|
436 |
self.handle_error_message(msg) |
|
437 |
if not silence: |
|
438 |
msg = _("Silence rule #%s does not exist.") % idsilence |
|
439 |
self.handle_error_message(msg) |
|
440 |
|
|
441 |
# - Si le supitem a été modifié, on vérifie qu'aucune |
|
442 |
# autre règle n'existe pour le nouveau supitem |
|
443 |
if silence.idsupitem != idsupitem: |
|
444 |
self.check_silence_rule_existence(idsupitem) |
|
445 |
|
|
446 |
# On supprime les états existants |
|
447 |
silence.states = [] |
|
448 |
|
|
449 |
# 2. Dans le cas d'une création : |
|
450 |
else: |
|
451 |
|
|
452 |
# - On s'assure qu'aucune autre règle n'existe pour le supitem |
|
453 |
self.check_silence_rule_existence(idsupitem) |
|
454 |
|
|
455 |
# - Et on crée l'objet représentant la règle |
|
456 |
silence = Silence() |
|
457 |
|
|
458 |
# Dans les 2 cas, on met à jour l'objet avec |
|
459 |
# les informations passées en paramètre |
|
460 |
silence.idsupitem = idsupitem |
|
461 |
silence.comment = comment |
|
462 |
silence.lastmodification = datetime.now().replace(microsecond=0) |
|
463 |
silence.author = user_name |
|
464 |
try: |
|
465 |
DBSession.add(silence) |
|
466 |
for state in states: |
|
467 |
s = DBSession.query(StateName |
|
468 |
).filter(StateName.statename == state).one() |
|
469 |
silence.states.append(s) |
|
470 |
DBSession.flush() |
|
471 |
except (IntegrityError, InvalidRequestError), e: |
|
472 |
msg = _('An exception has been raised while ' \ |
|
473 |
'updating the database: %s') % str(e) |
|
474 |
self.handle_error_message(msg) |
|
475 |
|
|
476 |
# On notifie l'opération dans les logs, on affiche un message de |
|
477 |
# succès, et on redirige le navigateur vers la liste des règles de |
|
478 |
# mise en silence. |
|
479 |
if idsilence: |
|
480 |
# Mise à jour d'une règle portant sur un service |
|
481 |
if hasattr(silence.supitem, 'servicename'): |
|
482 |
LOGGER.info(_( |
|
483 |
'User %(user)s (IP: %(ip)s) updated silence rule ' \ |
|
484 |
'#%(id)s for service %(service)s on host %(host)s.' |
|
485 |
) % { |
|
486 |
'user': user_name, |
|
487 |
'ip': user_ip, |
|
488 |
'id': idsilence, |
|
489 |
'host': host, |
|
490 |
'service': service |
|
491 |
}) |
|
492 |
flash(_( |
|
493 |
'Silence rule #%(id)s (host: %(host)s, service: ' \ |
|
494 |
'%(service)s) has been successfully updated.') % { |
|
495 |
'id': idsilence, |
|
496 |
'host': host, |
|
497 |
'service': service |
|
498 |
}) |
|
499 |
# Mise à jour d'une règle portant sur un hôte |
|
500 |
else: |
|
501 |
LOGGER.info(_( |
|
502 |
'User %(user)s (IP: %(ip)s) updated silence rule ' \ |
|
503 |
'#%(id)s for host %(host)s.') % { |
|
504 |
'user': user_name, |
|
505 |
'ip': user_ip, |
|
506 |
'id': idsilence, |
|
507 |
'host': host |
|
508 |
}) |
|
509 |
flash(_( |
|
510 |
'Silence rule #%(id)s (host: %(host)s) ' \ |
|
511 |
'has been successfully updated.') % { |
|
512 |
'id': idsilence, |
|
513 |
'host': host |
|
514 |
}) |
|
515 |
else: |
|
516 |
# Ajout d'une règle portant sur un service |
|
517 |
if service: |
|
518 |
LOGGER.info(_( |
|
519 |
'User %(user)s (IP: %(ip)s) added a silence rule (#' \ |
|
520 |
'%(id)s) for service %(service)s on host %(host)s.' |
|
521 |
) % { |
|
522 |
'user': user_name, |
|
523 |
'ip': user_ip, |
|
524 |
'id': idsilence, |
|
525 |
'host': host, |
|
526 |
'service': service |
|
527 |
}) |
|
528 |
flash(_('A new silence rule (#%(id)s) has been added for ' |
|
529 |
'service "%(service)s" on host "%(host)s".') % { |
|
530 |
'id': silence.idsilence, |
|
531 |
'service': service, |
|
532 |
'host': host |
|
533 |
}) |
|
534 |
# Ajout d'une règle portant sur un hôte |
|
535 |
else: |
|
536 |
LOGGER.info(_( |
|
537 |
'User %(user)s (IP: %(ip)s) added a silence rule ' \ |
|
538 |
'(#%(id)s) for host %(host)s.') % { |
|
539 |
'user': user_name, |
|
540 |
'ip': user_ip, |
|
541 |
'id': idsilence, |
|
542 |
'host': host |
|
543 |
}) |
|
544 |
flash(_('A new silence rule (#%(id)s) has been added for the ' |
|
545 |
'host "%(host)s".') % { |
|
546 |
'id': silence.idsilence, |
|
547 |
'host': host |
|
548 |
}) |
|
549 |
redirect('./') |
|
550 |
|
|
551 |
|
|
552 |
class DeleteSchema(schema.Schema): |
|
553 |
"""Schéma de validation de la méthode delete.""" |
|
554 |
id = All_( |
|
555 |
validators.Set(use_set=True), |
|
556 |
ForEach(validators.Int(min=1)), |
|
557 |
) |
|
558 |
|
|
559 |
@validate( |
|
560 |
validators=DeleteSchema(), |
|
561 |
error_handler = process_form_errors) |
|
562 |
@expose() |
|
563 |
@require(access_restriction) |
|
564 |
def delete(self, id): |
|
565 |
""" |
|
566 |
Suppression d'une règle ou d'une liste de règles de mise en silence. |
|
567 |
|
|
568 |
@param id: Liste des identifiants des règles à supprimer. |
|
569 |
@type id: C{list} of C{int} |
|
570 |
""" |
|
571 |
|
|
572 |
# TODO: Faire ce traitement dans le schéma de validation |
|
573 |
if not id: |
|
574 |
msg = _('No silence rule id specified.') |
|
575 |
self.handle_error_message(msg) |
|
576 |
id = list(id) |
|
577 |
|
|
578 |
# On recherche les règles dans la BDD. |
|
579 |
try: |
|
580 |
silences = DBSession.query(Silence |
|
581 |
).filter(Silence.idsilence.in_(id)).all() |
|
582 |
except InvalidRequestError, e: |
|
583 |
msg = _('An exception has been raised while ' \ |
|
584 |
'querying the database: %s') % str(e) |
|
585 |
self.handle_error_message(msg) |
|
586 |
|
|
587 |
# On s'assure que toutes les règles ont bien été trouvées dans la |
|
588 |
# base, faute de quoi on lève une erreur et on arrête le traitement |
|
589 |
if len(silences) != len(id): |
|
590 |
missing_ids = [ |
|
591 |
i for i in id if i not in [s.idsilence for s in silences]] |
|
592 |
if len(missing_ids) > 1: |
|
593 |
msg = _('Error: the following silence rules do not exist:' \ |
|
594 |
' %s.') % ", ".join('#' + str(i) for i in missing_ids) |
|
595 |
else: |
|
596 |
msg = _('Error: silence rule #%s does not exist.' |
|
597 |
) % ", ".join(str(i) for i in missing_ids) |
|
598 |
self.handle_error_message(msg) |
|
599 |
|
|
600 |
# On s'assure que l'utilisateur dispose bien des permissions nécessaires |
|
601 |
# pour supprimer chacune des règles |
|
602 |
user = get_current_user() |
|
603 |
for s in silences: |
|
604 |
if not s.supitem.is_allowed_for(user): |
|
605 |
msg = _("Silence rule #%s does not exist.") % s.idsilence |
|
606 |
self.handle_error_message(msg) |
|
607 |
|
|
608 |
# On supprime les règles dans la BDD. |
|
609 |
try: |
|
610 |
for silence in silences: |
|
611 |
DBSession.delete(silence) |
|
612 |
DBSession.flush() |
|
613 |
except InvalidRequestError, e: |
|
614 |
msg = _('An exception has been raised while ' \ |
|
615 |
'deleting the silence rules: %s') % str(e) |
|
616 |
self.handle_error_message(msg) |
|
617 |
|
|
618 |
# On notifie l'opération dans les logs |
|
619 |
user_name = user.user_name |
|
620 |
user_ip = request.remote_addr |
|
621 |
for s in silences: |
|
622 |
# Règle concernant un service de bas niveau |
|
623 |
if hasattr(s.supitem, 'servicename'): |
|
624 |
LOGGER.info(_( |
|
625 |
'User %(user)s (IP: %(ip)s) deleted silence rule ' \ |
|
626 |
'#%(id)s for service %(service)s on host ' \ |
|
627 |
'%(host)s') % { |
|
628 |
'user': user_name, |
|
629 |
'ip': user_ip, |
|
630 |
'id': s.idsilence, |
|
631 |
'host': s.supitem.host.name, |
|
632 |
'service': s.supitem.servicename |
|
633 |
}) |
|
634 |
# Règle concernant un hôte |
|
635 |
else: |
|
636 |
LOGGER.info(_( |
|
637 |
'User %(user)s (IP: %(ip)s) deleted silence rule ' \ |
|
638 |
'#%(id)s for host %(host)s') % { |
|
639 |
'user': user_name, |
|
640 |
'ip': user_ip, |
|
641 |
'id': s.idsilence, |
|
642 |
'host': s.supitem.name, |
|
643 |
}) |
|
644 |
|
|
645 |
# On affiche un message de succès |
|
646 |
if len(id) > 1: |
|
647 |
flash(_('The following silence rules have been successfully ' \ |
|
648 |
'deleted: %s.') % ", ".join(str(i) for i in id)) |
|
649 |
else: |
|
650 |
flash(_('Silence rule #%s has been successfully ' \ |
|
651 |
'deleted.') % id[0]) |
|
652 |
|
|
653 |
# On redirige le navigateur vers la page d'index |
|
654 |
redirect('./', ) |
|
655 |
|
vigiboard/i18n/de/LC_MESSAGES/vigiboard.po | ||
---|---|---|
8 | 8 |
"Project-Id-Version: vigiboard 2.0.0\n" |
9 | 9 |
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" |
10 | 10 |
"POT-Creation-Date: 2010-11-19 10:22+0100\n" |
11 |
"PO-Revision-Date: 2013-11-19 12:46+0100\n"
|
|
11 |
"PO-Revision-Date: 2014-02-03 10:52+0100\n"
|
|
12 | 12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
13 | 13 |
"Language-Team: de_DE <LL@li.org>\n" |
14 | 14 |
"Plural-Forms: nplurals=2; plural=(n != 1)\n" |
... | ... | |
22 | 22 |
msgid "Vigilo has detected a breakdown on the following collector(s): %(list)s" |
23 | 23 |
msgstr "" |
24 | 24 |
|
25 |
#: vigiboard/controllers/root.py:88 vigiboard/controllers/root.py:97
|
|
26 |
#: vigiboard/controllers/root.py:578
|
|
25 |
#: vigiboard/controllers/root.py:89 vigiboard/controllers/root.py:99
|
|
26 |
#: vigiboard/controllers/root.py:582 vigiboard/controllers/silence.py:70
|
|
27 | 27 |
msgid "You need to be authenticated" |
28 | 28 |
msgstr "Sie müssen sich authentifizieren" |
29 | 29 |
|
30 |
#: vigiboard/controllers/root.py:100
|
|
30 |
#: vigiboard/controllers/root.py:102
|
|
31 | 31 |
msgid "You don't have access to VigiBoard" |
32 | 32 |
msgstr "Sie haben keinen Zugang zu VigiBoard" |
33 | 33 |
|
34 |
#: vigiboard/controllers/root.py:248 vigiboard/controllers/root.py:544
|
|
34 |
#: vigiboard/controllers/root.py:252 vigiboard/controllers/root.py:548
|
|
35 | 35 |
#: vigiboard/controllers/vigiboardrequest.py:474 |
36 | 36 |
msgid "Apply" |
37 | 37 |
msgstr "Anwenden" |
38 | 38 |
|
39 |
#: vigiboard/controllers/root.py:384
|
|
39 |
#: vigiboard/controllers/root.py:388
|
|
40 | 40 |
msgid "No masked event or access denied" |
41 | 41 |
msgstr "Kein maskiertes Ereignis oder Zugriff verweigert" |
42 | 42 |
|
43 |
#: vigiboard/controllers/root.py:442
|
|
43 |
#: vigiboard/controllers/root.py:446
|
|
44 | 44 |
msgid "No such event or access denied" |
45 | 45 |
msgstr "Ereignis nicht vorhanden oder Zugriff verweigert" |
46 | 46 |
|
47 |
#: vigiboard/controllers/root.py:511
|
|
47 |
#: vigiboard/controllers/root.py:515
|
|
48 | 48 |
msgid "No such host/service" |
49 | 49 |
msgstr "Host/Service nicht vorhanden" |
50 | 50 |
|
51 |
#: vigiboard/controllers/root.py:534
|
|
51 |
#: vigiboard/controllers/root.py:538
|
|
52 | 52 |
msgid "No access to this host/service or no event yet" |
53 | 53 |
msgstr "Kein Zugang zu diesem Host/Service oder Ereignis noch nicht vorhanden" |
54 | 54 |
|
55 |
#: vigiboard/controllers/root.py:581
|
|
55 |
#: vigiboard/controllers/root.py:585
|
|
56 | 56 |
msgid "You don't have write access to VigiBoard" |
57 | 57 |
msgstr "Sie haben keinen Schreibzugriff auf VigiBoard" |
58 | 58 |
|
59 |
#: vigiboard/controllers/root.py:604
|
|
59 |
#: vigiboard/controllers/root.py:608
|
|
60 | 60 |
msgid "No event has been selected" |
61 | 61 |
msgstr "Es wurde kein Ereignis ausgewählt" |
62 | 62 |
|
63 |
#: vigiboard/controllers/root.py:632
|
|
63 |
#: vigiboard/controllers/root.py:636
|
|
64 | 64 |
msgid "" |
65 | 65 |
"Changes have occurred since the page was last displayed, your changes " |
66 | 66 |
"HAVE NOT been saved." |
... | ... | |
68 | 68 |
"Die seit der letzten Anzeige der Seite von Ihnen vorgenommenen Änderungen" |
69 | 69 |
" WURDEN NICHT gespeichert." |
70 | 70 |
|
71 |
#: vigiboard/controllers/root.py:638
|
|
71 |
#: vigiboard/controllers/root.py:642
|
|
72 | 72 |
msgid "No access to this event" |
73 | 73 |
msgstr "Kein Zugang zu diesem Ereignis " |
74 | 74 |
|
75 |
#: vigiboard/controllers/root.py:645
|
|
75 |
#: vigiboard/controllers/root.py:649
|
|
76 | 76 |
msgid "You don't have administrative access to VigiBoard" |
77 | 77 |
msgstr "Sie haben keine administrativen Zugriff auf VigiBoard" |
78 | 78 |
|
79 |
#: vigiboard/controllers/root.py:672
|
|
79 |
#: vigiboard/controllers/root.py:676
|
|
80 | 80 |
msgid "None" |
81 | 81 |
msgstr "" |
82 | 82 |
|
83 |
#: vigiboard/controllers/root.py:673
|
|
83 |
#: vigiboard/controllers/root.py:677
|
|
84 | 84 |
#, fuzzy |
85 | 85 |
msgid "Acknowledged" |
86 | 86 |
msgstr "Bestätigen" |
87 | 87 |
|
88 |
#: vigiboard/controllers/root.py:674
|
|
88 |
#: vigiboard/controllers/root.py:678
|
|
89 | 89 |
msgid "Acknowledged and closed" |
90 | 90 |
msgstr "" |
91 | 91 |
|
92 |
#: vigiboard/controllers/root.py:695
|
|
92 |
#: vigiboard/controllers/root.py:699
|
|
93 | 93 |
#, python-format |
94 | 94 |
msgid "" |
95 | 95 |
"User \"%(user)s\" (%(address)s) changed the trouble ticket from " |
96 | 96 |
"\"%(previous)s\" to \"%(new)s\" on event #%(idevent)d" |
97 | 97 |
msgstr "" |
98 | 98 |
|
99 |
#: vigiboard/controllers/root.py:740
|
|
99 |
#: vigiboard/controllers/root.py:744
|
|
100 | 100 |
#, python-format |
101 | 101 |
msgid "User \"%(user)s\" (%(address)s) forcefully closed event #%(idevent)d" |
102 | 102 |
msgstr "" |
103 | 103 |
|
104 |
#: vigiboard/controllers/root.py:773
|
|
104 |
#: vigiboard/controllers/root.py:777
|
|
105 | 105 |
#, python-format |
106 | 106 |
msgid "" |
107 | 107 |
"User \"%(user)s\" (%(address)s) changed the state from \"%(previous)s\" " |
108 | 108 |
"to \"%(new)s\" on event #%(idevent)d" |
109 | 109 |
msgstr "" |
110 | 110 |
|
111 |
#: vigiboard/controllers/root.py:785
|
|
111 |
#: vigiboard/controllers/root.py:789
|
|
112 | 112 |
msgid "Updated successfully" |
113 | 113 |
msgstr "Erfolgreich aktualisiert" |
114 | 114 |
|
115 |
#: vigiboard/controllers/root.py:810
|
|
115 |
#: vigiboard/controllers/root.py:814
|
|
116 | 116 |
#, fuzzy, python-format |
117 | 117 |
msgid "No such plugin '%s'" |
118 | 118 |
msgstr "Plug-In \"%s\" nicht vorhanden" |
119 | 119 |
|
120 |
#: vigiboard/controllers/root.py:852
|
|
120 |
#: vigiboard/controllers/root.py:856
|
|
121 | 121 |
msgid "No such incident or insufficient permissions" |
122 | 122 |
msgstr "Ereignis nicht vorhanden oder unzureichende Berechtigungen" |
123 | 123 |
|
124 |
#: vigiboard/controllers/root.py:964
|
|
124 |
#: vigiboard/controllers/root.py:968
|
|
125 | 125 |
#, python-format |
126 | 126 |
msgid "Next %(limit)s" |
127 | 127 |
msgstr "" |
128 | 128 |
|
129 |
#. TRANSLATORS: Format de date et heure Python/JavaScript. |
|
130 |
#. TRANSLATORS: |
|
131 |
#. http://www.dynarch.com/static/jscalendar-1.0/doc/html/reference.html#node_sec_5.3.5 |
|
132 |
#. TRANSLATORS: http://docs.python.org/release/2.5/lib/module-time.html |
|
133 |
#: vigiboard/controllers/plugins/date.py:57 vigiboard/lib/dateformat.py:34 |
|
134 |
#: vigiboard/lib/dateformat.py:46 |
|
129 |
#: vigiboard/controllers/silence.py:73 |
|
130 |
msgid "Insufficient privileges for this action" |
|
131 |
msgstr "" |
|
132 |
|
|
133 |
#: vigiboard/controllers/silence.py:172 |
|
135 | 134 |
#, python-format |
136 |
msgid "%Y-%m-%d %I:%M:%S %p" |
|
137 |
msgstr "%Y-%m-%d %I:%M:%S %p" |
|
135 |
msgid "Another rule already exists for service '%s' on host '%s'." |
|
136 |
msgstr "" |
|
137 |
|
|
138 |
#: vigiboard/controllers/silence.py:176 |
|
139 |
#, python-format |
|
140 |
msgid "Another rule already exists for host '%s'." |
|
141 |
msgstr "" |
|
142 |
|
|
143 |
#: vigiboard/controllers/silence.py:258 |
|
144 |
#: vigiboard/controllers/plugins/hostname.py:38 |
|
145 |
msgid "Host" |
|
146 |
msgstr "Host" |
|
147 |
|
|
148 |
#: vigiboard/controllers/silence.py:259 |
|
149 |
#: vigiboard/controllers/plugins/servicename.py:41 |
|
150 |
msgid "Service" |
|
151 |
msgstr "Service" |
|
152 |
|
|
153 |
#: vigiboard/controllers/silence.py:260 |
|
154 |
msgid "States" |
|
155 |
msgstr "" |
|
156 |
|
|
157 |
#: vigiboard/controllers/silence.py:261 |
|
158 |
msgid "Last modification" |
|
159 |
msgstr "" |
|
160 |
|
|
161 |
#: vigiboard/controllers/silence.py:262 |
|
162 |
msgid "Author" |
|
163 |
msgstr "" |
|
164 |
|
|
165 |
#: vigiboard/controllers/silence.py:263 |
|
166 |
msgid "Comment" |
|
167 |
msgstr "" |
|
168 |
|
|
169 |
#: vigiboard/controllers/silence.py:313 vigiboard/controllers/silence.py:412 |
|
170 |
#: vigiboard/controllers/silence.py:434 vigiboard/controllers/silence.py:583 |
|
171 |
#, python-format |
|
172 |
msgid "An exception has been raised while querying the database: %s" |
|
173 |
msgstr "" |
|
174 |
|
|
175 |
#: vigiboard/controllers/silence.py:317 vigiboard/controllers/silence.py:324 |
|
176 |
#: vigiboard/controllers/silence.py:438 vigiboard/controllers/silence.py:605 |
|
177 |
#, python-format |
|
178 |
msgid "Silence rule #%s does not exist." |
|
179 |
msgstr "" |
|
180 |
|
|
181 |
#: vigiboard/controllers/silence.py:395 |
|
182 |
msgid "No state specified for the silence rule." |
|
183 |
msgstr "" |
|
184 |
|
|
185 |
#: vigiboard/controllers/silence.py:417 |
|
186 |
#, python-format |
|
187 |
msgid "Host '%s' does not exist." |
|
188 |
msgstr "" |
|
189 |
|
|
190 |
#: vigiboard/controllers/silence.py:420 |
|
191 |
#, python-format |
|
192 |
msgid "Service '%s' does not exist for host '%s'." |
|
193 |
msgstr "" |
|
194 |
|
|
195 |
#: vigiboard/controllers/silence.py:472 |
|
196 |
#, python-format |
|
197 |
msgid "An exception has been raised while updating the database: %s" |
|
198 |
msgstr "" |
|
199 |
|
|
200 |
#: vigiboard/controllers/silence.py:482 |
|
201 |
#, python-format |
|
202 |
msgid "" |
|
203 |
"User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for service " |
|
204 |
"%(service)s on host %(host)s." |
|
205 |
msgstr "" |
|
206 |
|
|
207 |
#: vigiboard/controllers/silence.py:492 |
|
208 |
#, python-format |
|
209 |
msgid "" |
|
210 |
"Silence rule #%(id)s (host: %(host)s, service: %(service)s) has been " |
|
211 |
"successfully updated." |
|
212 |
msgstr "" |
|
213 |
|
|
214 |
#: vigiboard/controllers/silence.py:501 |
|
215 |
#, python-format |
|
216 |
msgid "User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for host %(host)s." |
|
217 |
msgstr "" |
|
218 |
|
|
219 |
#: vigiboard/controllers/silence.py:509 |
|
220 |
#, python-format |
|
221 |
msgid "Silence rule #%(id)s (host: %(host)s) has been successfully updated." |
|
222 |
msgstr "" |
|
223 |
|
|
224 |
#: vigiboard/controllers/silence.py:518 |
|
225 |
#, python-format |
|
226 |
msgid "" |
|
227 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for service " |
|
228 |
"%(service)s on host %(host)s." |
|
229 |
msgstr "" |
|
230 |
|
|
231 |
#: vigiboard/controllers/silence.py:528 |
|
232 |
#, python-format |
|
233 |
msgid "" |
|
234 |
"A new silence rule (#%(id)s) has been added for service \"%(service)s\" " |
|
235 |
"on host \"%(host)s\"." |
|
236 |
msgstr "" |
|
237 |
|
|
238 |
#: vigiboard/controllers/silence.py:536 |
|
239 |
#, python-format |
|
240 |
msgid "" |
|
241 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for host " |
|
242 |
"%(host)s." |
|
243 |
msgstr "" |
|
244 |
|
|
245 |
#: vigiboard/controllers/silence.py:544 |
|
246 |
#, python-format |
|
247 |
msgid "A new silence rule (#%(id)s) has been added for the host \"%(host)s\"." |
|
248 |
msgstr "" |
|
249 |
|
|
250 |
#: vigiboard/controllers/silence.py:574 |
|
251 |
msgid "No silence rule id specified." |
|
252 |
msgstr "" |
|
253 |
|
|
254 |
#: vigiboard/controllers/silence.py:593 |
|
255 |
#, python-format |
|
256 |
msgid "Error: the following silence rules do not exist: %s." |
|
257 |
msgstr "" |
|
258 |
|
|
259 |
#: vigiboard/controllers/silence.py:596 |
|
260 |
#, python-format |
|
261 |
msgid "Error: silence rule #%s does not exist." |
|
262 |
msgstr "" |
|
263 |
|
|
264 |
#: vigiboard/controllers/silence.py:614 |
|
265 |
#, python-format |
|
266 |
msgid "An exception has been raised while deleting the silence rules: %s" |
|
267 |
msgstr "" |
|
268 |
|
|
269 |
#: vigiboard/controllers/silence.py:624 |
|
270 |
#, python-format |
|
271 |
msgid "" |
|
272 |
"User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for service " |
|
273 |
"%(service)s on host %(host)s" |
|
274 |
msgstr "" |
|
275 |
|
|
276 |
#: vigiboard/controllers/silence.py:636 |
|
277 |
#, python-format |
|
278 |
msgid "User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for host %(host)s" |
|
279 |
msgstr "" |
|
280 |
|
|
281 |
#: vigiboard/controllers/silence.py:647 |
|
282 |
#, python-format |
|
283 |
msgid "The following silence rules have been successfully deleted: %s." |
|
284 |
msgstr "" |
|
285 |
|
|
286 |
#: vigiboard/controllers/silence.py:650 |
|
287 |
#, python-format |
|
288 |
msgid "Silence rule #%s has been successfully deleted." |
|
289 |
msgstr "" |
|
138 | 290 |
|
139 |
#: vigiboard/controllers/plugins/date.py:63
|
|
291 |
#: vigiboard/controllers/plugins/date.py:38
|
|
140 | 292 |
msgid "Last occurrence" |
141 | 293 |
msgstr "" |
142 | 294 |
|
143 |
#: vigiboard/controllers/plugins/date.py:66
|
|
295 |
#: vigiboard/controllers/plugins/date.py:41
|
|
144 | 296 |
msgid "Between" |
145 | 297 |
msgstr "" |
146 | 298 |
|
147 |
#: vigiboard/controllers/plugins/date.py:67
|
|
148 |
#: vigiboard/controllers/plugins/date.py:76
|
|
299 |
#: vigiboard/controllers/plugins/date.py:42
|
|
300 |
#: vigiboard/controllers/plugins/date.py:51
|
|
149 | 301 |
#: vigiboard/controllers/plugins/groups.py:41 |
150 | 302 |
msgid "Choose" |
151 | 303 |
msgstr "Auswählen" |
152 | 304 |
|
153 |
#: vigiboard/controllers/plugins/date.py:75
|
|
305 |
#: vigiboard/controllers/plugins/date.py:50
|
|
154 | 306 |
msgid "And" |
155 | 307 |
msgstr "" |
156 | 308 |
|
... | ... | |
166 | 318 |
msgid "High-Level Service" |
167 | 319 |
msgstr "" |
168 | 320 |
|
169 |
#: vigiboard/controllers/plugins/hostname.py:38 |
|
170 |
msgid "Host" |
|
171 |
msgstr "Host" |
|
172 |
|
|
173 | 321 |
#: vigiboard/controllers/plugins/output.py:38 |
174 | 322 |
msgid "Output" |
175 | 323 |
msgstr "Ausgabe" |
... | ... | |
178 | 326 |
msgid "Priority" |
179 | 327 |
msgstr "Priorität" |
180 | 328 |
|
181 |
#: vigiboard/controllers/plugins/servicename.py:41 |
|
182 |
msgid "Service" |
|
183 |
msgstr "Service" |
|
184 |
|
|
185 | 329 |
#: vigiboard/controllers/plugins/status.py:53 |
186 | 330 |
msgid "All alerts" |
187 | 331 |
msgstr "" |
... | ... | |
208 | 352 |
msgid "Acknowledgement Status" |
209 | 353 |
msgstr "Bestätigungsstatus" |
210 | 354 |
|
355 |
#. TRANSLATORS: Format de date et heure Python/JavaScript. |
|
356 |
#. TRANSLATORS: |
|
357 |
#. http://www.dynarch.com/static/jscalendar-1.0/doc/html/reference.html#node_sec_5.3.5 |
|
358 |
#. TRANSLATORS: http://docs.python.org/release/2.5/lib/module-time.html |
|
359 |
#: vigiboard/lib/dateformat.py:35 vigiboard/lib/dateformat.py:58 |
|
360 |
#: vigiboard/lib/dateformat.py:70 |
|
361 |
#, python-format |
|
362 |
msgid "%Y-%m-%d %I:%M:%S %p" |
|
363 |
msgstr "%Y-%m-%d %I:%M:%S %p" |
|
364 |
|
|
211 | 365 |
#: vigiboard/public/js/main.js:39 |
212 | 366 |
msgid "Search Event" |
213 | 367 |
msgstr "" |
... | ... | |
221 | 375 |
msgid "Unable to save preferences" |
222 | 376 |
msgstr "" |
223 | 377 |
|
378 |
#: vigiboard/public/js/silence.js:63 |
|
379 |
msgid "Are you sure you want to delete this rule?" |
|
380 |
msgstr "" |
|
381 |
|
|
382 |
#: vigiboard/public/js/silence.js:64 |
|
383 |
msgid "Silence rule #{id}" |
|
384 |
msgstr "" |
|
385 |
|
|
386 |
#: vigiboard/public/js/silence.js:65 |
|
387 |
msgid "Delete this rule" |
|
388 |
msgstr "" |
|
389 |
|
|
390 |
#: vigiboard/public/js/silence.js:79 |
|
391 |
msgid "No" |
|
392 |
msgstr "" |
|
393 |
|
|
224 | 394 |
#: vigiboard/widgets/edit_event.py:34 |
225 | 395 |
msgid "No change" |
226 | 396 |
msgstr "Keine Änderung" |
... | ... | |
281 | 451 |
msgid "Search" |
282 | 452 |
msgstr "Suchen" |
283 | 453 |
|
284 |
#~ msgid "From" |
|
285 |
#~ msgstr "Von" |
|
286 |
|
|
287 |
#~ msgid "To" |
|
288 |
#~ msgstr "Bis" |
|
289 |
|
vigiboard/i18n/en/LC_MESSAGES/vigiboard.po | ||
---|---|---|
1 | 1 |
# English translations for vigilo-vigiboard. |
2 |
# Copyright (C) 2013 ORGANIZATION
|
|
2 |
# Copyright (C) 2014 ORGANIZATION
|
|
3 | 3 |
# This file is distributed under the same license as the vigilo-vigiboard |
4 | 4 |
# project. |
5 |
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
|
5 |
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
|
|
6 | 6 |
# |
7 | 7 |
msgid "" |
8 | 8 |
msgstr "" |
9 | 9 |
"Project-Id-Version: vigilo-vigiboard 3.3\n" |
10 | 10 |
"Report-Msgid-Bugs-To: contact@projet-vigilo.org\n" |
11 |
"POT-Creation-Date: 2013-11-19 12:46+0100\n"
|
|
12 |
"PO-Revision-Date: 2013-11-19 12:46+0100\n"
|
|
11 |
"POT-Creation-Date: 2014-02-03 10:52+0100\n"
|
|
12 |
"PO-Revision-Date: 2014-02-03 10:52+0100\n"
|
|
13 | 13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
14 | 14 |
"Language-Team: en <LL@li.org>\n" |
15 | 15 |
"Plural-Forms: nplurals=2; plural=(n != 1)\n" |
... | ... | |
23 | 23 |
msgid "Vigilo has detected a breakdown on the following collector(s): %(list)s" |
24 | 24 |
msgstr "Vigilo has detected a breakdown on the following collector(s): %(list)s" |
25 | 25 |
|
26 |
#: vigiboard/controllers/root.py:88 vigiboard/controllers/root.py:97
|
|
27 |
#: vigiboard/controllers/root.py:578
|
|
26 |
#: vigiboard/controllers/root.py:89 vigiboard/controllers/root.py:99
|
|
27 |
#: vigiboard/controllers/root.py:582 vigiboard/controllers/silence.py:70
|
|
28 | 28 |
msgid "You need to be authenticated" |
29 | 29 |
msgstr "You need to be authenticated" |
30 | 30 |
|
31 |
#: vigiboard/controllers/root.py:100
|
|
31 |
#: vigiboard/controllers/root.py:102
|
|
32 | 32 |
msgid "You don't have access to VigiBoard" |
33 | 33 |
msgstr "You don't have access to VigiBoard" |
34 | 34 |
|
35 |
#: vigiboard/controllers/root.py:248 vigiboard/controllers/root.py:544
|
|
35 |
#: vigiboard/controllers/root.py:252 vigiboard/controllers/root.py:548
|
|
36 | 36 |
#: vigiboard/controllers/vigiboardrequest.py:474 |
37 | 37 |
msgid "Apply" |
38 | 38 |
msgstr "Apply" |
39 | 39 |
|
40 |
#: vigiboard/controllers/root.py:384
|
|
40 |
#: vigiboard/controllers/root.py:388
|
|
41 | 41 |
msgid "No masked event or access denied" |
42 | 42 |
msgstr "No masked event or access denied" |
43 | 43 |
|
44 |
#: vigiboard/controllers/root.py:442
|
|
44 |
#: vigiboard/controllers/root.py:446
|
|
45 | 45 |
msgid "No such event or access denied" |
46 | 46 |
msgstr "No such event or access denied" |
47 | 47 |
|
48 |
#: vigiboard/controllers/root.py:511
|
|
48 |
#: vigiboard/controllers/root.py:515
|
|
49 | 49 |
msgid "No such host/service" |
50 | 50 |
msgstr "No such host/service" |
51 | 51 |
|
52 |
#: vigiboard/controllers/root.py:534
|
|
52 |
#: vigiboard/controllers/root.py:538
|
|
53 | 53 |
msgid "No access to this host/service or no event yet" |
54 | 54 |
msgstr "No access to this host/service or no event yet" |
55 | 55 |
|
56 |
#: vigiboard/controllers/root.py:581
|
|
56 |
#: vigiboard/controllers/root.py:585
|
|
57 | 57 |
msgid "You don't have write access to VigiBoard" |
58 | 58 |
msgstr "You don't have write access to VigiBoard" |
59 | 59 |
|
60 |
#: vigiboard/controllers/root.py:604
|
|
60 |
#: vigiboard/controllers/root.py:608
|
|
61 | 61 |
msgid "No event has been selected" |
62 | 62 |
msgstr "No event has been selected" |
63 | 63 |
|
64 |
#: vigiboard/controllers/root.py:632
|
|
64 |
#: vigiboard/controllers/root.py:636
|
|
65 | 65 |
msgid "" |
66 | 66 |
"Changes have occurred since the page was last displayed, your changes " |
67 | 67 |
"HAVE NOT been saved." |
... | ... | |
69 | 69 |
"Changes have occurred since the page was last displayed, your changes " |
70 | 70 |
"HAVE NOT been saved." |
71 | 71 |
|
72 |
#: vigiboard/controllers/root.py:638
|
|
72 |
#: vigiboard/controllers/root.py:642
|
|
73 | 73 |
msgid "No access to this event" |
74 | 74 |
msgstr "No access to this event" |
75 | 75 |
|
76 |
#: vigiboard/controllers/root.py:645
|
|
76 |
#: vigiboard/controllers/root.py:649
|
|
77 | 77 |
msgid "You don't have administrative access to VigiBoard" |
78 | 78 |
msgstr "You don't have administrative access to VigiBoard" |
79 | 79 |
|
80 |
#: vigiboard/controllers/root.py:672
|
|
80 |
#: vigiboard/controllers/root.py:676
|
|
81 | 81 |
msgid "None" |
82 | 82 |
msgstr "None" |
83 | 83 |
|
84 |
#: vigiboard/controllers/root.py:673
|
|
84 |
#: vigiboard/controllers/root.py:677
|
|
85 | 85 |
msgid "Acknowledged" |
86 | 86 |
msgstr "Acknowledged" |
87 | 87 |
|
88 |
#: vigiboard/controllers/root.py:674
|
|
88 |
#: vigiboard/controllers/root.py:678
|
|
89 | 89 |
msgid "Acknowledged and closed" |
90 | 90 |
msgstr "Acknowledged and closed" |
91 | 91 |
|
92 |
#: vigiboard/controllers/root.py:695
|
|
92 |
#: vigiboard/controllers/root.py:699
|
|
93 | 93 |
#, python-format |
94 | 94 |
msgid "" |
95 | 95 |
"User \"%(user)s\" (%(address)s) changed the trouble ticket from " |
... | ... | |
98 | 98 |
"User \"%(user)s\" (%(address)s) changed the trouble ticket from " |
99 | 99 |
"\"%(previous)s\" to \"%(new)s\" on event #%(idevent)d" |
100 | 100 |
|
101 |
#: vigiboard/controllers/root.py:740
|
|
101 |
#: vigiboard/controllers/root.py:744
|
|
102 | 102 |
#, python-format |
103 | 103 |
msgid "User \"%(user)s\" (%(address)s) forcefully closed event #%(idevent)d" |
104 | 104 |
msgstr "User \"%(user)s\" (%(address)s) forcefully closed event #%(idevent)d" |
105 | 105 |
|
106 |
#: vigiboard/controllers/root.py:773
|
|
106 |
#: vigiboard/controllers/root.py:777
|
|
107 | 107 |
#, python-format |
108 | 108 |
msgid "" |
109 | 109 |
"User \"%(user)s\" (%(address)s) changed the state from \"%(previous)s\" " |
... | ... | |
112 | 112 |
"User \"%(user)s\" (%(address)s) changed the state from \"%(previous)s\" " |
113 | 113 |
"to \"%(new)s\" on event #%(idevent)d" |
114 | 114 |
|
115 |
#: vigiboard/controllers/root.py:785
|
|
115 |
#: vigiboard/controllers/root.py:789
|
|
116 | 116 |
msgid "Updated successfully" |
117 | 117 |
msgstr "Updated successfully" |
118 | 118 |
|
119 |
#: vigiboard/controllers/root.py:810
|
|
119 |
#: vigiboard/controllers/root.py:814
|
|
120 | 120 |
#, python-format |
121 | 121 |
msgid "No such plugin '%s'" |
122 | 122 |
msgstr "No such plugin '%s'" |
123 | 123 |
|
124 |
#: vigiboard/controllers/root.py:852
|
|
124 |
#: vigiboard/controllers/root.py:856
|
|
125 | 125 |
msgid "No such incident or insufficient permissions" |
126 | 126 |
msgstr "No such incident or insufficient permissions" |
127 | 127 |
|
128 |
#: vigiboard/controllers/root.py:964
|
|
128 |
#: vigiboard/controllers/root.py:968
|
|
129 | 129 |
#, python-format |
130 | 130 |
msgid "Next %(limit)s" |
131 | 131 |
msgstr "Next %(limit)s" |
132 | 132 |
|
133 |
#. TRANSLATORS: Format de date et heure Python/JavaScript. |
|
134 |
#. TRANSLATORS: |
|
135 |
#. http://www.dynarch.com/static/jscalendar-1.0/doc/html/reference.html#node_sec_5.3.5 |
|
136 |
#. TRANSLATORS: http://docs.python.org/release/2.5/lib/module-time.html |
|
137 |
#: vigiboard/controllers/plugins/date.py:57 vigiboard/lib/dateformat.py:34 |
|
138 |
#: vigiboard/lib/dateformat.py:46 |
|
133 |
#: vigiboard/controllers/silence.py:73 |
|
134 |
msgid "Insufficient privileges for this action" |
|
135 |
msgstr "Insufficient privileges for this action" |
|
136 |
|
|
137 |
#: vigiboard/controllers/silence.py:172 |
|
139 | 138 |
#, python-format |
140 |
msgid "%Y-%m-%d %I:%M:%S %p" |
|
141 |
msgstr "%Y-%m-%d %I:%M:%S %p" |
|
139 |
msgid "Another rule already exists for service '%s' on host '%s'." |
|
140 |
msgstr "Another rule already exists for service '%s' on host '%s'." |
|
141 |
|
|
142 |
#: vigiboard/controllers/silence.py:176 |
|
143 |
#, python-format |
|
144 |
msgid "Another rule already exists for host '%s'." |
|
145 |
msgstr "Another rule already exists for host '%s'." |
|
146 |
|
|
147 |
#: vigiboard/controllers/silence.py:258 |
|
148 |
#: vigiboard/controllers/plugins/hostname.py:38 |
|
149 |
msgid "Host" |
|
150 |
msgstr "Host" |
|
151 |
|
|
152 |
#: vigiboard/controllers/silence.py:259 |
|
153 |
#: vigiboard/controllers/plugins/servicename.py:41 |
|
154 |
msgid "Service" |
|
155 |
msgstr "Service" |
|
156 |
|
|
157 |
#: vigiboard/controllers/silence.py:260 |
|
158 |
msgid "States" |
|
159 |
msgstr "States" |
|
160 |
|
|
161 |
#: vigiboard/controllers/silence.py:261 |
|
162 |
msgid "Last modification" |
|
163 |
msgstr "Last modification" |
|
164 |
|
|
165 |
#: vigiboard/controllers/silence.py:262 |
|
166 |
msgid "Author" |
|
167 |
msgstr "Author" |
|
168 |
|
|
169 |
#: vigiboard/controllers/silence.py:263 |
|
170 |
msgid "Comment" |
|
171 |
msgstr "Comment" |
|
172 |
|
|
173 |
#: vigiboard/controllers/silence.py:313 vigiboard/controllers/silence.py:412 |
|
174 |
#: vigiboard/controllers/silence.py:434 vigiboard/controllers/silence.py:583 |
|
175 |
#, python-format |
|
176 |
msgid "An exception has been raised while querying the database: %s" |
|
177 |
msgstr "An exception has been raised while querying the database: %s" |
|
178 |
|
|
179 |
#: vigiboard/controllers/silence.py:317 vigiboard/controllers/silence.py:324 |
|
180 |
#: vigiboard/controllers/silence.py:438 vigiboard/controllers/silence.py:605 |
|
181 |
#, python-format |
|
182 |
msgid "Silence rule #%s does not exist." |
|
183 |
msgstr "Silence rule #%s does not exist." |
|
184 |
|
|
185 |
#: vigiboard/controllers/silence.py:395 |
|
186 |
msgid "No state specified for the silence rule." |
|
187 |
msgstr "No state specified for the silence rule." |
|
188 |
|
|
189 |
#: vigiboard/controllers/silence.py:417 |
|
190 |
#, python-format |
|
191 |
msgid "Host '%s' does not exist." |
|
192 |
msgstr "Host '%s' does not exist." |
|
193 |
|
|
194 |
#: vigiboard/controllers/silence.py:420 |
|
195 |
#, python-format |
|
196 |
msgid "Service '%s' does not exist for host '%s'." |
|
197 |
msgstr "Service '%s' does not exist for host '%s'." |
|
198 |
|
|
199 |
#: vigiboard/controllers/silence.py:472 |
|
200 |
#, python-format |
|
201 |
msgid "An exception has been raised while updating the database: %s" |
|
202 |
msgstr "An exception has been raised while updating the database: %s" |
|
203 |
|
|
204 |
#: vigiboard/controllers/silence.py:482 |
|
205 |
#, python-format |
|
206 |
msgid "" |
|
207 |
"User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for service " |
|
208 |
"%(service)s on host %(host)s." |
|
209 |
msgstr "" |
|
210 |
"User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for service " |
|
211 |
"%(service)s on host %(host)s." |
|
212 |
|
|
213 |
#: vigiboard/controllers/silence.py:492 |
|
214 |
#, python-format |
|
215 |
msgid "" |
|
216 |
"Silence rule #%(id)s (host: %(host)s, service: %(service)s) has been " |
|
217 |
"successfully updated." |
|
218 |
msgstr "" |
|
219 |
"Silence rule #%(id)s (host: %(host)s, service: %(service)s) has been " |
|
220 |
"successfully updated." |
|
221 |
|
|
222 |
#: vigiboard/controllers/silence.py:501 |
|
223 |
#, python-format |
|
224 |
msgid "User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for host %(host)s." |
|
225 |
msgstr "User %(user)s (IP: %(ip)s) updated silence rule #%(id)s for host %(host)s." |
|
226 |
|
|
227 |
#: vigiboard/controllers/silence.py:509 |
|
228 |
#, python-format |
|
229 |
msgid "Silence rule #%(id)s (host: %(host)s) has been successfully updated." |
|
230 |
msgstr "Silence rule #%(id)s (host: %(host)s) has been successfully updated." |
|
231 |
|
|
232 |
#: vigiboard/controllers/silence.py:518 |
|
233 |
#, python-format |
|
234 |
msgid "" |
|
235 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for service " |
|
236 |
"%(service)s on host %(host)s." |
|
237 |
msgstr "" |
|
238 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for service " |
|
239 |
"%(service)s on host %(host)s." |
|
142 | 240 |
|
143 |
#: vigiboard/controllers/plugins/date.py:63 |
|
241 |
#: vigiboard/controllers/silence.py:528 |
|
242 |
#, python-format |
|
243 |
msgid "" |
|
244 |
"A new silence rule (#%(id)s) has been added for service \"%(service)s\" " |
|
245 |
"on host \"%(host)s\"." |
|
246 |
msgstr "" |
|
247 |
"A new silence rule (#%(id)s) has been added for service \"%(service)s\" " |
|
248 |
"on host \"%(host)s\"." |
|
249 |
|
|
250 |
#: vigiboard/controllers/silence.py:536 |
|
251 |
#, python-format |
|
252 |
msgid "" |
|
253 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for host " |
|
254 |
"%(host)s." |
|
255 |
msgstr "" |
|
256 |
"User %(user)s (IP: %(ip)s) added a silence rule (#%(id)s) for host " |
|
257 |
"%(host)s." |
|
258 |
|
|
259 |
#: vigiboard/controllers/silence.py:544 |
|
260 |
#, python-format |
|
261 |
msgid "A new silence rule (#%(id)s) has been added for the host \"%(host)s\"." |
|
262 |
msgstr "A new silence rule (#%(id)s) has been added for the host \"%(host)s\"." |
|
263 |
|
|
264 |
#: vigiboard/controllers/silence.py:574 |
|
265 |
msgid "No silence rule id specified." |
|
266 |
msgstr "No silence rule id specified." |
|
267 |
|
|
268 |
#: vigiboard/controllers/silence.py:593 |
|
269 |
#, python-format |
|
270 |
msgid "Error: the following silence rules do not exist: %s." |
|
271 |
msgstr "Error: the following silence rules do not exist: %s." |
|
272 |
|
|
273 |
#: vigiboard/controllers/silence.py:596 |
|
274 |
#, python-format |
|
275 |
msgid "Error: silence rule #%s does not exist." |
|
276 |
msgstr "Error: silence rule #%s does not exist." |
|
277 |
|
|
278 |
#: vigiboard/controllers/silence.py:614 |
|
279 |
#, python-format |
|
280 |
msgid "An exception has been raised while deleting the silence rules: %s" |
|
281 |
msgstr "An exception has been raised while deleting the silence rules: %s" |
|
282 |
|
|
283 |
#: vigiboard/controllers/silence.py:624 |
|
284 |
#, python-format |
|
285 |
msgid "" |
|
286 |
"User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for service " |
|
287 |
"%(service)s on host %(host)s" |
|
288 |
msgstr "" |
|
289 |
"User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for service " |
|
290 |
"%(service)s on host %(host)s" |
|
291 |
|
|
292 |
#: vigiboard/controllers/silence.py:636 |
|
293 |
#, python-format |
|
294 |
msgid "User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for host %(host)s" |
|
295 |
msgstr "User %(user)s (IP: %(ip)s) deleted silence rule #%(id)s for host %(host)s" |
|
296 |
|
Also available in: Unified diff