Best Python code snippet using localstack_python
mkeventd.py
Source:mkeventd.py
1#!/usr/bin/python2# -*- encoding: utf-8; py-indent-offset: 4 -*-3# +------------------------------------------------------------------+4# | ____ _ _ __ __ _ __ |5# | / ___| |__ ___ ___| | __ | \/ | |/ / |6# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |7# | | |___| | | | __/ (__| < | | | | . \ |8# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |9# | |10# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |11# +------------------------------------------------------------------+12#13# This file is part of Check_MK.14# The official homepage is at http://mathias-kettner.de/check_mk.15#16# check_mk is free software; you can redistribute it and/or modify it17# under the terms of the GNU General Public License as published by18# the Free Software Foundation in version 2. check_mk is distributed19# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-20# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A21# PARTICULAR PURPOSE. See the GNU General Public License for more de-22# tails. You should have received a copy of the GNU General Public23# License along with GNU Make; see the file COPYING. If not, write24# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,25# Boston, MA 02110-1301 USA.26import mkeventd, defaults27import zipfile28import cStringIO29mkeventd_enabled = config.mkeventd_enabled30# main_config_file = defaults.check_mk_configdir + "/mkeventd.mk"31mkeventd_config_dir = defaults.default_config_dir + "/mkeventd.d/wato/"32if defaults.omd_root:33 mkeventd_status_file = defaults.omd_root + "/var/mkeventd/status"34#.35# .--ValueSpecs----------------------------------------------------------.36# | __ __ _ ____ |37# | \ \ / /_ _| |_ _ ___/ ___| _ __ ___ ___ ___ |38# | \ \ / / _` | | | | |/ _ \___ \| '_ \ / _ \/ __/ __| |39# | \ V / (_| | | |_| | __/___) | |_) | __/ (__\__ \ |40# | \_/ \__,_|_|\__,_|\___|____/| .__/ \___|\___|___/ |41# | |_| |42# +----------------------------------------------------------------------+43# | Declarations of the structure of rules and actions |44# '----------------------------------------------------------------------'45substitute_help = _("""46The following macros will be substituted by value from the actual event:47<table class=help>48<tr><td class=tt>$ID$</td><td>Event ID</td></tr>49<tr><td class=tt>$COUNT$</td><td>Number of occurrances</td></tr>50<tr><td class=tt>$TEXT$</td><td>Message text</td></tr>51<tr><td class=tt>$FIRST$</td><td>Time of the first occurrance (time stamp)</td></tr>52<tr><td class=tt>$LAST$</td><td>Time of the most recent occurrance</td></tr>53<tr><td class=tt>$COMMENT$</td><td>Event comment</td></tr>54<tr><td class=tt>$SL$</td><td>Service Level</td></tr>55<tr><td class=tt>$HOST$</td><td>Host name (as sent by syslog)</td></tr>56<tr><td class=tt>$CONTACT$</td><td>Contact information</td></tr>57<tr><td class=tt>$APPLICATION$</td><td>Syslog tag / Application</td></tr>58<tr><td class=tt>$PID$</td><td>Process ID of the origin process</td></tr>59<tr><td class=tt>$PRIORITY$</td><td>Syslog Priority</td></tr>60<tr><td class=tt>$FACILITY$</td><td>Syslog Facility</td></tr>61<tr><td class=tt>$RULE_ID$</td><td>ID of the rule</td></tr>62<tr><td class=tt>$STATE$</td><td>State of the event (0/1/2/3)</td></tr>63<tr><td class=tt>$PHASE$</td><td>Phase of the event (open in normal situations, closed when cancelling)</td></tr>64<tr><td class=tt>$OWNER$</td><td>Owner of the event</td></tr>65<tr><td class=tt>$MATCH_GROUPS$</td><td>Text groups from regular expression match, separated by spaces</td></tr>66<tr><td class=tt>$MATCH_GROUP_1$</td><td>Text of the first match group from expression match</td></tr>67<tr><td class=tt>$MATCH_GROUP_2$</td><td>Text of the second match group from expression match</td></tr>68<tr><td class=tt>$MATCH_GROUP_3$</td><td>Text of the third match group from expression match (and so on...)</td></tr>69</table>70"""71)72class ActionList(ListOf):73 def __init__(self, vs, **kwargs):74 ListOf.__init__(self, vs, **kwargs)75 def validate_value(self, value, varprefix):76 ListOf.validate_value(self, value, varprefix)77 action_ids = [ v["id"] for v in value ]78 legacy_rules, rule_packs = load_mkeventd_rules()79 for rule_pack in rule_packs:80 for rule in rule_pack["rules"]:81 for action_id in rule.get("actions", []):82 if action_id not in action_ids + ["@NOTIFY"]:83 raise MKUserError(varprefix, _("You are missing the action with the ID <b>%s</b>, "84 "which is still used in some rules.") % action_id)85vs_mkeventd_actions = \86 ActionList(87 Foldable(88 Dictionary(89 title = _("Action"),90 optional_keys = False,91 elements = [92 ( "id",93 ID(94 title = _("Action ID"),95 help = _("A unique ID of this action that is used as an internal "96 "reference in the configuration. Changing the ID is not "97 "possible if still rules refer to this ID."),98 allow_empty = False,99 size = 12,100 )101 ),102 ( "title",103 TextUnicode(104 title = _("Title"),105 help = _("A descriptive title of this action."),106 allow_empty = False,107 size = 64,108 attrencode = True,109 )110 ),111 ( "disabled",112 Checkbox(113 title = _("Disable"),114 label = _("Currently disable execution of this action"),115 )116 ),117 ( "hidden",118 Checkbox(119 title = _("Hide from Status GUI"),120 label = _("Do not offer this action as a command on open events"),121 help = _("If you enabled this option, then this action will not "122 "be available as an interactive user command. It is usable "123 "as an ad-hoc action when a rule fires, nevertheless."),124 ),125 ),126 ( "action",127 CascadingDropdown(128 title = _("Type of Action"),129 help = _("Choose the type of action to perform"),130 choices = [131 ( "email",132 _("Send Email"),133 Dictionary(134 optional_keys = False,135 elements = [136 ( "to",137 TextAscii(138 title = _("Recipient Email address"),139 allow_empty = False,140 attrencode = True,141 ),142 ),143 ( "subject",144 TextUnicode(145 title = _("Subject"),146 allow_empty = False,147 size = 64,148 attrencode = True,149 ),150 ),151 ( "body",152 TextAreaUnicode(153 title = _("Body"),154 help = _("Text-body of the email to send. ") + substitute_help,155 cols = 64,156 rows = 10,157 attrencode = True,158 ),159 ),160 ]161 )162 ),163 ( "script",164 _("Execute Shell Script"),165 Dictionary(166 optional_keys = False,167 elements = [168 ( "script",169 TextAreaUnicode(170 title = _("Script body"),171 help = _("This script will be executed using the BASH shell. ") + substitute_help,172 cols = 64,173 rows = 10,174 attrencode = True,175 )176 ),177 ]178 )179 ),180 ]181 ),182 ),183 ],184 ),185 title_function = lambda value: not value["id"] and _("New Action") or (value["id"] + " - " + value["title"]),186 ),187 title = _("Actions (Emails & Scripts)"),188 help = _("Configure that possible actions that can be performed when a "189 "rule triggers and also manually by a user."),190 totext = _("%d actions"),191 add_label = _("Add new action"),192 )193class RuleState(CascadingDropdown):194 def __init__(self, **kwargs):195 choices = [196 ( 0, _("OK")),197 ( 1, _("WARN")),198 ( 2, _("CRIT")),199 ( 3, _("UNKNOWN")),200 (-1, _("(set by syslog)")),201 ('text_pattern', _('(set by message text)'),202 Dictionary(203 elements = [204 ('2', RegExpUnicode(205 title = _("CRIT Pattern"),206 help = _("When the given regular expression (infix search) matches "207 "the events state is set to CRITICAL."),208 size = 64,209 )),210 ('1', RegExpUnicode(211 title = _("WARN Pattern"),212 help = _("When the given regular expression (infix search) matches "213 "the events state is set to WARNING."),214 size = 64,215 )),216 ('0', RegExpUnicode(217 title = _("OK Pattern"),218 help = _("When the given regular expression (infix search) matches "219 "the events state is set to OK."),220 size = 64,221 )),222 ],223 help = _('Individual patterns matching the text (which must have been matched by '224 'the generic "text to match pattern" before) which set the state of the '225 'generated event depending on the match.<br><br>'226 'First the CRITICAL pattern is tested, then WARNING and OK at last. '227 'When none of the patterns matches, the events state is set to UNKNOWN.'),228 )229 ),230 ]231 CascadingDropdown.__init__(self, choices = choices, **kwargs)232vs_mkeventd_rule_pack = Dictionary(233 title = _("Rule pack properties"),234 render = "form",235 elements = [236 ( "id",237 ID(238 title = _("Rule pack ID"),239 help = _("A unique ID of this rule pack."),240 allow_empty = False,241 size = 12,242 )),243 ( "title",244 TextUnicode(245 title = _("Title"),246 help = _("A descriptive title for this rule pack"),247 allow_empty = False,248 size = 64,249 )250 ),251 ( "disabled",252 Checkbox(253 title = _("Disable"),254 label = _("Currently disable execution of all rules in the pack"),255 )256 ),257 ],258 optional_keys = False,259)260vs_mkeventd_rule = Dictionary(261 title = _("Rule Properties"),262 elements = [263 ( "id",264 ID(265 title = _("Rule ID"),266 help = _("A unique ID of this rule. Each event will remember the rule "267 "it was classified with by its rule ID."),268 allow_empty = False,269 size = 12,270 )),271 ] + rule_option_elements() +272 [273 ( "drop",274 DropdownChoice(275 title = _("Rule type"),276 choices = [277 ( False, _("Normal operation - process message according to action settings") ),278 ( True, _("Do not perform any action, drop this message, stop processing") ),279 ( "skip_pack", _("Skip this rule pack, continue rule execution with next rule pack") ),280 ],281 help = _("With this option you can implement rules that rule out certain message from the "282 "procession totally. Either you can totally abort further rule execution, or "283 "you can skip just the current rule pack and continue with the next one."),284 )285 ),286 ( "state",287 RuleState(288 title = _("State"),289 help = _("The monitoring state that this event will trigger."),290 default_value = -1,291 )),292 ( "sl",293 DropdownChoice(294 title = _("Service Level"),295 choices = mkeventd.service_levels,296 prefix_values = True,297 ),298 ),299 ( "contact_groups",300 ListOf(301 GroupSelection("contact"),302 title = _("Contact Groups"),303 help = _("When displaying events in the Check_MK GUI, you can make a user see only events "304 "for hosts he is a contact for. When you expect this rule to receive events from "305 "hosts that are <i>not</i> known to the monitoring, you can specify contact groups "306 "for visibility here. Notes: 1. If you activate this option and do not specify "307 "any group, then users with restricted permissions can never see these events."308 "2. If both the host is found in the monitoring <b>and</b> contact groups are "309 "specified in the rule then usually the host's contact groups have precedence. But you "310 "can change that via a global setting in the section <i>User Interface</i>."),311 movable = False,312 )313 ),314 ( "actions",315 ListChoice(316 title = _("Actions"),317 help = _("Actions to automatically perform when this event occurs"),318 choices = mkeventd.action_choices,319 )320 ),321 ( "cancel_actions",322 ListChoice(323 title = _("Actions when cancelling"),324 help = _("Actions to automatically perform when an event is being cancelled."),325 choices = mkeventd.action_choices,326 )327 ),328 ( "cancel_action_phases",329 DropdownChoice(330 title = _("Do Cancelling-Actions when..."),331 choices = [332 ( "always", _("Always when an event is being cancelled")),333 ( "open", _("Only when the cancelled event is in phase OPEN")),334 ],335 help = _("With this setting you can prevent actions to be executed when "336 "events are being cancelled that are in the phases DELAYED or COUNTING."),337 )),338 ( "autodelete",339 Checkbox(340 title = _("Automatic Deletion"),341 label = _("Delete event immediately after the actions"),342 help = _("Incoming messages might trigger actions (when configured above), "343 "afterwards only an entry in the event history will be left. There "344 "will be no \"open event\" to be handled by the administrators."),345 )346 ),347 ( "count",348 Dictionary(349 title = _("Count messages in defined interval"),350 help = _("With this option you can make the rule being executed not before "351 "the matching message is seen a couple of times in a defined "352 "time interval. Also counting activates the aggregation of messages "353 "that result from the same rule into one event, even if <i>count</i> is "354 "set to 1."),355 optional_keys = False,356 columns = 2,357 elements = [358 ( "count",359 Integer(360 title = _("Count until triggered"),361 help = _("That many times the message must occur until an event is created"),362 minvalue = 1,363 ),364 ),365 ( "period",366 Age(367 title = _("Time period for counting"),368 help = _("If in this time range the configured number of time the rule is "369 "triggered, an event is being created. If the required count is not reached "370 "then the count is reset to zero."),371 default_value = 86400,372 ),373 ),374 ( "algorithm",375 DropdownChoice(376 title = _("Algorithm"),377 help = _("Select how the count is computed. The algorithm <i>Interval</i> will count the "378 "number of messages from the first occurrance and reset this counter as soon as "379 "the interval is elapsed or the maximum count has reached. The token bucket algorithm "380 "does not work with intervals but simply decreases the current count by one for "381 "each partial time interval. Please refer to the online documentation for more details."),382 choices = [383 ( "interval", _("Interval")),384 ( "tokenbucket", _("Token Bucket")),385 ( "dynabucket", _("Dynamic Token Bucket")),386 ],387 default_value = "interval")388 ),389 ( "count_ack",390 Checkbox(391 label = _("Continue counting when event is <b>acknowledged</b>"),392 help = _("Otherwise counting will start from one with a new event for "393 "the next rule match."),394 default_value = False,395 )396 ),397 ( "separate_host",398 Checkbox(399 label = _("Force separate events for different <b>hosts</b>"),400 help = _("When aggregation is turned on and the rule matches for "401 "two different hosts then these two events will be kept "402 "separate if you check this box."),403 default_value = True,404 ),405 ),406 ( "separate_application",407 Checkbox(408 label = _("Force separate events for different <b>applications</b>"),409 help = _("When aggregation is turned on and the rule matches for "410 "two different applications then these two events will be kept "411 "separate if you check this box."),412 default_value = True,413 ),414 ),415 ( "separate_match_groups",416 Checkbox(417 label = _("Force separate events for different <b>match groups</b>"),418 help = _("When you use subgroups in the regular expression of your "419 "match text then you can have different values for the matching "420 "groups be reflected in different events."),421 default_value = True,422 ),423 ),424 ],425 )426 ),427 ( "expect",428 Dictionary(429 title = _("Expect regular messages"),430 help = _("With this option activated you can make the Event Console monitor "431 "that a certain number of messages are <b>at least</b> seen within "432 "each regular time interval. Otherwise an event will be created. "433 "The options <i>week</i>, <i>two days</i> and <i>day</i> refer to "434 "periodic intervals aligned at 00:00:00 on the 1st of January 1970. "435 "You can specify a relative offset in hours in order to re-align this "436 "to any other point of time."),437 optional_keys = False,438 columns = 2,439 elements = [440 ( "interval",441 CascadingDropdown(442 title = _("Interval"),443 html_separator = " ",444 choices = [445 ( 7*86400, _("week"),446 Integer(447 label = _("Timezone offset"),448 unit = _("hours"),449 default_value = 0,450 minvalue = - 167,451 maxvalue = 167,452 )453 ),454 ( 2*86400, _("two days"),455 Integer(456 label = _("Timezone offset"),457 unit = _("hours"),458 default_value = 0,459 minvalue = - 47,460 maxvalue = 47,461 )462 ),463 ( 86400, _("day"),464 DropdownChoice(465 label = _("in timezone"),466 choices = [467 ( -12, _("UTC -12 hours") ),468 ( -11, _("UTC -11 hours") ),469 ( -10, _("UTC -10 hours") ),470 ( -9, _("UTC -9 hours") ),471 ( -8, _("UTC -8 hours") ),472 ( -7, _("UTC -7 hours") ),473 ( -6, _("UTC -6 hours") ),474 ( -5, _("UTC -5 hours") ),475 ( -4, _("UTC -4 hours") ),476 ( -3, _("UTC -3 hours") ),477 ( -2, _("UTC -2 hours") ),478 ( -1, _("UTC -1 hour") ),479 ( 0, _("UTC") ),480 ( 1, _("UTC +1 hour") ),481 ( 2, _("UTC +2 hours") ),482 ( 3, _("UTC +3 hours") ),483 ( 4, _("UTC +4 hours") ),484 ( 5, _("UTC +5 hours") ),485 ( 6, _("UTC +8 hours") ),486 ( 7, _("UTC +7 hours") ),487 ( 8, _("UTC +8 hours") ),488 ( 9, _("UTC +9 hours") ),489 ( 10, _("UTC +10 hours") ),490 ( 11, _("UTC +11 hours") ),491 ( 12, _("UTC +12 hours") ),492 ],493 default_value = 0,494 )495 ),496 ( 3600, _("hour") ),497 ( 900, _("15 minutes") ),498 ( 300, _("5 minutes") ),499 ( 60, _("minute") ),500 ( 10, _("10 seconds") ),501 ],502 default_value = 3600,503 )504 ),505 ( "count",506 Integer(507 title = _("Number of expected messages in each interval"),508 minvalue = 1,509 )510 ),511 ( "merge",512 DropdownChoice(513 title = _("Merge with open event"),514 help = _("If there already exists an open event because of absent "515 "messages according to this rule, you can optionally merge "516 "the new incident with the exising event or create a new "517 "event for each interval with absent messages."),518 choices = [519 ( "open", _("Merge if there is an open un-acknowledged event") ),520 ( "acked", _("Merge even if there is an acknowledged event") ),521 ( "never", _("Create a new event for each incident - never merge") ),522 ],523 default_value = "open",524 )525 ),526 ])527 ),528 ( "delay",529 Age(530 title = _("Delay event creation"),531 help = _("The creation of an event will be delayed by this time period. This "532 "does only make sense for events that can be cancelled by a negative "533 "rule."))534 ),535 ( "livetime",536 Tuple(537 title = _("Limit event livetime"),538 help = _("If you set a livetime of an event, then it will automatically be "539 "deleted after that time if, even if no action has taken by the user. You can "540 "decide whether to expire open, acknowledged or both types of events. The lifetime "541 "always starts when the event is entering the open state."),542 elements = [543 Age(),544 ListChoice(545 choices = [546 ( "open", _("Expire events that are in the state <i>open</i>") ),547 ( "ack", _("Expire events that are in the state <i>acknowledged</i>") ),548 ],549 default_value = [ "open" ],550 )551 ],552 ),553 ),554 ( "match",555 RegExpUnicode(556 title = _("Text to match"),557 help = _("The rules does only apply when the given regular expression matches "558 "the message text (infix search)."),559 size = 64,560 )561 ),562 ( "match_host",563 RegExpUnicode(564 title = _("Match host"),565 help = _("The rules does only apply when the given regular expression matches "566 "the host name the message originates from. Note: in some cases the "567 "event might use the IP address instead of the host name."),568 )569 ),570 ( "match_ipaddress",571 IPv4Network(572 title = _("Match original source IP address"),573 help = _("The rules does only apply when the event is being received from a "574 "certain IP address. You can specify either a single IP address "575 "or an IPv4 network in the notation X.X.X.X/Bits."),576 )577 ),578 ( "match_application",579 RegExpUnicode(580 title = _("Match syslog application (tag)"),581 help = _("Regular expression for matching the syslog tag (case insenstive)"),582 )583 ),584 ( "match_priority",585 Tuple(586 title = _("Match syslog priority"),587 help = _("Define a range of syslog priorities this rule matches"),588 orientation = "horizontal",589 show_titles = False,590 elements = [591 DropdownChoice(label = _("from:"), choices = mkeventd.syslog_priorities, default_value = 4),592 DropdownChoice(label = _(" to:"), choices = mkeventd.syslog_priorities, default_value = 0),593 ],594 ),595 ),596 ( "match_facility",597 DropdownChoice(598 title = _("Match syslog facility"),599 help = _("Make the rule match only if the message has a certain syslog facility. "600 "Messages not having a facility are classified as <tt>user</tt>."),601 choices = mkeventd.syslog_facilities,602 )603 ),604 ( "match_sl",605 Tuple(606 title = _("Match service level"),607 help = _("This setting is only useful for events that result from monitoring notifications "608 "sent by Check_MK. Those can set a service level already in the event. In such a "609 "case you can make this rule match only certain service levels. Events that do not "),610 orientation = "horizontal",611 show_titles = False,612 elements = [613 DropdownChoice(label = _("from:"), choices = mkeventd.service_levels, prefix_values = True),614 DropdownChoice(label = _(" to:"), choices = mkeventd.service_levels, prefix_values = True),615 ],616 ),617 ),618 ( "match_timeperiod",619 TimeperiodSelection(620 title = _("Match only during timeperiod"),621 help = _("Match this rule only during times where the selected timeperiod from the monitoring "622 "system is active. The Timeperiod definitions are taken from the monitoring core that "623 "is running on the same host or OMD site as the event daemon. Please note, that this "624 "selection only offers timeperiods that are defined with WATO."),625 ),626 ),627 ( "match_ok",628 RegExpUnicode(629 title = _("Text to cancel event(s)"),630 help = _("If a matching message appears with this text, then events created "631 "by this rule will automatically be cancelled if host, application and match groups match. "632 "If this expression has fewer match groups than \"Text to match\", "633 "it will cancel all events where the specified groups match the same number "634 "of groups in the initial text, starting from the left."),635 size = 64,636 )637 ),638 ( "cancel_priority",639 Tuple(640 title = _("Syslog priority to cancel event"),641 help = _("If the priority of the event lies withing this range and either no text to cancel "642 "is specified or that text also matched, then events created with this rule will "643 "automatically be cancelled (if host, application and match groups match)."),644 orientation = "horizontal",645 show_titles = False,646 elements = [647 DropdownChoice(label = _("from:"), choices = mkeventd.syslog_priorities, default_value = 7),648 DropdownChoice(label = _(" to:"), choices = mkeventd.syslog_priorities, default_value = 5),649 ],650 ),651 ),652 ( "invert_matching",653 Checkbox(654 title = _("Invert matching"),655 label = _("Negate match: Execute this rule if the upper conditions are <b>not</b> fulfilled."),656 help = _("By activating this checkbox the complete combined rule conditions will be inverted. That "657 "means that this rule with be executed, if at least on of the conditions does <b>not</b> match. "658 "This can e.g. be used for skipping a rule pack if the message text does not contain <tt>ORA-</tt>. "659 "Please note: When an inverted rule matches there can never be match groups."),660 )),661 ( "set_text",662 TextUnicode(663 title = _("Rewrite message text"),664 help = _("Replace the message text with this text. If you have bracketed "665 "groups in the text to match, then you can use the placeholders "666 "<tt>\\1</tt>, <tt>\\2</tt>, etc. for inserting the first, second "667 "etc matching group.") +668 _("The placeholder <tt>\\0</tt> will be replaced by the original text. "669 "This allows you to add new information in front or at the end."),670 size = 64,671 allow_empty = False,672 attrencode = True,673 )674 ),675 ( "set_host",676 TextUnicode(677 title = _("Rewrite hostname"),678 help = _("Replace the host name with this text. If you have bracketed "679 "groups in the text to match, then you can use the placeholders "680 "<tt>\\1</tt>, <tt>\\2</tt>, etc. for inserting the first, second "681 "etc matching group.") +682 _("The placeholder <tt>\\0</tt> will be replaced by the original text "683 "to match. Note that as an alternative, you may also use the rule "684 "Hostname translation for Incoming Messages in the Global Settings "685 "of the EC to accomplish your task."),686 allow_empty = False,687 attrencode = True,688 )689 ),690 ( "set_application",691 TextUnicode(692 title = _("Rewrite application"),693 help = _("Replace the application (syslog tag) with this text. If you have bracketed "694 "groups in the text to match, then you can use the placeholders "695 "<tt>\\1</tt>, <tt>\\2</tt>, etc. for inserting the first, second "696 "etc matching group.") +697 _("The placeholder <tt>\\0</tt> will be replaced by the original text. "698 "This allows you to add new information in front or at the end."),699 allow_empty = False,700 attrencode = True,701 )702 ),703 ( "set_comment",704 TextUnicode(705 title = _("Add comment"),706 help = _("Attach a comment to the event. If you have bracketed "707 "groups in the text to match, then you can use the placeholders "708 "<tt>\\1</tt>, <tt>\\2</tt>, etc. for inserting the first, second "709 "etc matching group.") +710 _("The placeholder <tt>\\0</tt> will be replaced by the original text. "711 "This allows you to add new information in front or at the end."),712 size = 64,713 allow_empty = False,714 attrencode = True,715 )716 ),717 ( "set_contact",718 TextUnicode(719 title = _("Add contact information"),720 help = _("Attach information about a contact person. If you have bracketed "721 "groups in the text to match, then you can use the placeholders "722 "<tt>\\1</tt>, <tt>\\2</tt>, etc. for inserting the first, second "723 "etc matching group.") +724 _("The placeholder <tt>\\0</tt> will be replaced by the original text. "725 "This allows you to add new information in front or at the end."),726 size = 64,727 allow_empty = False,728 attrencode = True,729 )730 ),731 ],732 optional_keys = [ "delay", "livetime", "count", "expect", "match_priority", "match_priority",733 "match_facility", "match_sl", "match_host", "match_ipaddress", "match_application", "match_timeperiod",734 "set_text", "set_host", "set_application", "set_comment",735 "set_contact", "cancel_priority", "match_ok", "contact_groups", ],736 headers = [737 ( _("Rule Properties"), [ "id", "description", "comment", "docu_url", "disabled" ] ),738 ( _("Matching Criteria"), [ "match", "match_host", "match_ipaddress", "match_application", "match_priority", "match_facility",739 "match_sl", "match_ok", "cancel_priority", "match_timeperiod", "invert_matching" ]),740 ( _("Outcome & Action"), [ "state", "sl", "contact_groups", "actions", "cancel_actions", "cancel_action_phases", "drop", "autodelete" ]),741 ( _("Counting & Timing"), [ "count", "expect", "delay", "livetime", ]),742 ( _("Rewriting"), [ "set_text", "set_host", "set_application", "set_comment", "set_contact" ]),743 ],744 render = "form",745 form_narrow = True,746)747# VS for simulating an even748vs_mkeventd_event = Dictionary(749 title = _("Event Simulator"),750 help = _("You can simulate an event here and check out, which rules are matching."),751 render = "form",752 form_narrow = True,753 optional_keys = False,754 elements = [755 ( "text",756 TextUnicode(757 title = _("Message Text"),758 size = 80,759 allow_empty = False,760 default_value = _("Still nothing happened."),761 attrencode = True),762 ),763 ( "application",764 TextUnicode(765 title = _("Application Name"),766 help = _("The syslog tag"),767 size = 40,768 default_value = _("Foobar-Daemon"),769 allow_empty = True,770 attrencode = True),771 ),772 ( "host",773 TextUnicode(774 title = _("Host Name"),775 help = _("The host name of the event"),776 size = 40,777 default_value = _("myhost089"),778 allow_empty = True,779 attrencode = True,780 regex = "^\\S*$",781 regex_error = _("The host name may not contain spaces."),782 )783 ),784 ( "ipaddress",785 IPv4Address(786 title = _("IP Address"),787 help = _("Original IP address the event was received from"),788 default_value = "1.2.3.4",789 )),790 ( "priority",791 DropdownChoice(792 title = _("Syslog Priority"),793 choices = mkeventd.syslog_priorities,794 default_value = 5,795 )796 ),797 ( "facility",798 DropdownChoice(799 title = _("Syslog Facility"),800 choices = mkeventd.syslog_facilities,801 default_value = 1,802 )803 ),804 ("sl", DropdownChoice(805 title = _("Service Level"),806 choices = mkeventd.service_levels,807 prefix_values = True,808 )),809 ])810#.811# .--Load & Save---------------------------------------------------------.812# | _ _ ___ ____ |813# | | | ___ __ _ __| | ( _ ) / ___| __ ___ _____ |814# | | | / _ \ / _` |/ _` | / _ \/\ \___ \ / _` \ \ / / _ \ |815# | | |__| (_) | (_| | (_| | | (_> < ___) | (_| |\ V / __/ |816# | |_____\___/ \__,_|\__,_| \___/\/ |____/ \__,_| \_/ \___| |817# | |818# +----------------------------------------------------------------------+819# | Loading and saving of rule packages |820# '----------------------------------------------------------------------'821def load_mkeventd_rules():822 filename = mkeventd_config_dir + "rules.mk"823 if not os.path.exists(filename):824 return [], []825 # Old versions define rules. We convert this into826 # rule_packs but keep the old rule intact so the827 # user can switch back to his old configuration.828 vars = { "rules" : [], "rule_packs" : [] }829 execfile(filename, vars, vars)830 # Convert some data fields into a new format831 for rule in vars["rules"]:832 if "livetime" in rule:833 livetime = rule["livetime"]834 if type(livetime) != tuple:835 rule["livetime"] = ( livetime, ["open"] )836 # Convert old plain rules into a list of one rule pack837 if vars["rules"] and not vars["rule_packs"]:838 vars["rule_packs"] = [{839 "id" : "default",840 "title" : _("Default rule pack"),841 "rules" : vars["rules"],842 "disabled" : False,843 }]844 # Add information about rule hits: If we are running on OMD then we know845 # the path to the state retention file of mkeventd and can read the rule846 # statistics directly from that file.847 if defaults.omd_root and os.path.exists(mkeventd_status_file):848 mkeventd_status = eval(file(mkeventd_status_file).read())849 rule_stats = mkeventd_status["rule_stats"]850 for rule_pack in vars["rule_packs"]:851 pack_hits = 0852 for rule in rule_pack["rules"]:853 hits = rule_stats.get(rule["id"], 0)854 rule["hits"] = hits855 pack_hits += hits856 rule_pack["hits"] = pack_hits857 # Return old rules also, for easy rolling back to old config858 return vars["rules"], vars["rule_packs"]859def save_mkeventd_rules(legacy_rules, rule_packs):860 make_nagios_directory(defaults.default_config_dir + "/mkeventd.d")861 make_nagios_directory(mkeventd_config_dir)862 out = create_user_file(mkeventd_config_dir + "rules.mk", "w")863 out.write("# Written by WATO\n# encoding: utf-8\n\n")864 try:865 if config.mkeventd_pprint_rules:866 out.write("rules += \\\n%s\n\n" % pprint.pformat(legacy_rules))867 out.write("rule_packs += \\\n%s\n" % pprint.pformat(rule_packs))868 return869 except:870 pass871 out.write("rules += \\\n%r\n\n" % legacy_rules)872 out.write("rule_packs += \\\n%r\n" % rule_packs)873#.874# .--WATO Modes----------------------------------------------------------.875# | __ ___ _____ ___ __ __ _ |876# | \ \ / / \|_ _/ _ \ | \/ | ___ __| | ___ ___ |877# | \ \ /\ / / _ \ | || | | | | |\/| |/ _ \ / _` |/ _ \/ __| |878# | \ V V / ___ \| || |_| | | | | | (_) | (_| | __/\__ \ |879# | \_/\_/_/ \_\_| \___/ |_| |_|\___/ \__,_|\___||___/ |880# | |881# +----------------------------------------------------------------------+882# | The actual configuration modes for all rules, one rule and the |883# | activation of the changes. |884# '----------------------------------------------------------------------'885def mode_mkeventd_rule_packs(phase):886 legacy_rules, rule_packs = load_mkeventd_rules()887 if phase == "title":888 return _("Event Console Rule Packages")889 elif phase == "buttons":890 home_button()891 mkeventd_changes_button()892 if config.may("mkeventd.edit"):893 html.context_button(_("New Rule Pack"), html.makeuri_contextless([("mode", "mkeventd_edit_rule_pack")]), "new")894 html.context_button(_("Reset Counters"),895 make_action_link([("mode", "mkeventd_rule_packs"), ("_reset_counters", "1")]), "resetcounters")896 mkeventd_status_button()897 mkeventd_config_button()898 mkeventd_mibs_button()899 return900 if phase == "action":901 action_outcome = event_simulation_action()902 if action_outcome:903 return action_outcome904 # Deletion of rule packs905 if html.has_var("_delete"):906 nr = int(html.var("_delete"))907 rule_pack = rule_packs[nr]908 c = wato_confirm(_("Confirm rule pack deletion"),909 _("Do you really want to delete the rule pack <b>%s</b> <i>%s</i> with <b>%s</b> rules?" %910 (rule_pack["id"], rule_pack["title"], len(rule_pack["rules"]))))911 if c:912 log_mkeventd("delete-rule-pack", _("Deleted rule pack %s") % rule_pack["id"])913 del rule_packs[nr]914 save_mkeventd_rules(legacy_rules, rule_packs)915 elif c == False:916 return ""917 # Reset all rule hit counteres918 elif html.has_var("_reset_counters"):919 c = wato_confirm(_("Confirm counter reset"),920 _("Do you really want to reset all rule hit counters in <b>all rule packs</b> to zero?"))921 if c:922 mkeventd.query("COMMAND RESETCOUNTERS")923 log_mkeventd("counter-reset", _("Resetted all rule hit counters to zero"))924 elif c == False:925 return ""926 # Copy rules from master927 # TODO: Wo ist der Knopf dafür?928 elif html.has_var("_copy_rules"):929 c = wato_confirm(_("Confirm copying rules"),930 _("Do you really want to copy all event rules from the master and "931 "replace your local configuration with them?"))932 if c:933 copy_rules_from_master()934 log_mkeventd("copy-rules-from-master", _("Copied the event rules from the master "935 "into the local configuration"))936 return None, _("Copied rules from master")937 elif c == False:938 return ""939 # Move rule packages940 elif html.has_var("_move"):941 from_pos = int(html.var("_move"))942 to_pos = int(html.var("_where"))943 rule_pack = rule_packs[from_pos]944 del rule_packs[from_pos] # make to_pos now match!945 rule_packs[to_pos:to_pos] = [rule_pack]946 save_mkeventd_rules(legacy_rules, rule_packs)947 log_mkeventd("move-rule-pack", _("Changed position of rule pack %s") % rule_pack["id"])948 return949 rep_mode = mkeventd.replication_mode()950 if rep_mode in [ "sync", "takeover" ]:951 copy_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_copy_rules", "1")])952 html.show_warning(_("WARNING: This Event Console is currently running as a replication "953 "slave. The rules edited here will not be used. Instead a copy of the rules of the "954 "master are being used in the case of a takeover. The same holds for the event "955 "actions in the global settings.<br><br>If you want you can copy the ruleset of "956 "the master into your local slave configuration: ") + \957 '<a href="%s">' % copy_url + _("Copy Rules From Master") + '</a>')958 # Simulator959 event = show_event_simulator()960 if not rule_packs:961 html.message(_("You have not created any rule packs yet. The Event Console is useless unless "962 "you have activated <i>Force message archiving</i> in the global settings."))963 else:964 have_match = False965 table.begin(limit=None, sortable=False, title=_("Rule packs"))966 for nr, rule_pack in enumerate(rule_packs):967 table.row()968 delete_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_delete", nr)])969 top_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_move", nr), ("_where", 0)])970 bottom_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_move", nr), ("_where", len(rule_packs)-1)])971 up_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_move", nr), ("_where", nr-1)])972 down_url = make_action_link([("mode", "mkeventd_rule_packs"), ("_move", nr), ("_where", nr+1)])973 edit_url = html.makeuri_contextless([("mode", "mkeventd_edit_rule_pack"), ("edit", nr)])974 # Cloning does not work. Rule IDs would not be unique. So drop it for a while975 # clone_url = html.makeuri_contextless([("mode", "mkeventd_edit_rule_pack"), ("clone", nr)])976 rules_url = html.makeuri_contextless([("mode", "mkeventd_rules"), ("rule_pack", rule_pack["id"])])977 table.cell(_("Actions"), css="buttons")978 html.icon_button(edit_url, _("Edit properties of this rule pack"), "edit")979 # Cloning does not work until we have unique IDs980 # html.icon_button(clone_url, _("Create a copy of this rule pack"), "clone")981 html.icon_button(delete_url, _("Delete this rule pack"), "delete")982 html.icon_button(rules_url, _("Edit the rules in this pack"), "mkeventd_rules")983 if not rule_pack is rule_packs[0]:984 html.icon_button(top_url, _("Move this rule pack to the top"), "top")985 html.icon_button(up_url, _("Move this rule pack one position up"), "up")986 else:987 html.empty_icon_button()988 html.empty_icon_button()989 if not rule_pack is rule_packs[-1]:990 html.icon_button(down_url, _("Move this rule pack one position down"), "down")991 html.icon_button(bottom_url, _("Move this rule pack to the bottom"), "bottom")992 else:993 html.empty_icon_button()994 html.empty_icon_button()995 # Icon for disabling996 table.cell("", css="buttons")997 if rule_pack["disabled"]:998 html.icon(_("This rule pack is currently disabled. None of its rules will be applied."), "disabled")999 # Simulation of all rules in this pack1000 elif event:1001 matches = 01002 match_groups = None1003 cancelling_matches = 01004 skips = 01005 for rule in rule_pack["rules"]:1006 result = mkeventd.event_rule_matches(rule, event)1007 if type(result) == tuple:1008 cancelling, groups = result1009 if not cancelling and rule.get("drop") == "skip_pack":1010 matches += 11011 skips = 11012 break1013 if matches == 0:1014 match_groups = groups # show groups of first (= decisive) match1015 if cancelling and matches == 0:1016 cancelling_matches += 11017 matches += 11018 if matches == 0:1019 msg = _("None of the rules in this pack matches")1020 icon = "rulenmatch"1021 else:1022 msg = _("Number of matching rules in this pack: %d") % matches1023 if skips:1024 msg += _(", the first match skips this rule pack")1025 icon = "rulenmatch"1026 else:1027 if cancelling:1028 msg += _(", first match is a cancelling match")1029 if groups:1030 msg += _(", match groups of decisive match: %s") % ",".join([ g or _('<None>') for g in groups ])1031 if have_match:1032 msg += _(", but it is overruled by a match in a previous rule pack.")1033 icon = "rulepmatch"1034 else:1035 icon = "rulematch"1036 have_match = True1037 html.icon(msg, icon)1038 table.cell(_("ID"), rule_pack["id"])1039 table.cell(_("Title"), html.attrencode(rule_pack["title"]))1040 table.cell(_("Rules"), css="number")1041 html.write('<a href="%s">%d</a>' % (rules_url, len(rule_pack["rules"])))1042 if defaults.omd_root:1043 hits = rule_pack.get('hits')1044 table.cell(_("Hits"), hits != None and hits or '', css="number")1045 table.end()1046def show_event_simulator():1047 event = config.load_user_file("simulated_event", {})1048 html.begin_form("simulator")1049 vs_mkeventd_event.render_input("event", event)1050 forms.end()1051 html.hidden_fields()1052 html.button("simulate", _("Try out"))1053 html.button("_generate", _("Generate Event!"))1054 html.end_form()1055 html.write("<br>")1056 if html.var("simulate") or html.var("_generate"):1057 return vs_mkeventd_event.from_html_vars("event")1058 else:1059 return None1060def event_simulation_action():1061 # Validation of input for rule simulation (no further action here)1062 if html.var("simulate") or html.var("_generate"):1063 event = vs_mkeventd_event.from_html_vars("event")1064 vs_mkeventd_event.validate_value(event, "event")1065 config.save_user_file("simulated_event", event)1066 if html.has_var("_generate") and html.check_transaction():1067 if not event.get("application"):1068 raise MKUserError("event_p_application", _("Please specify an application name"))1069 if not event.get("host"):1070 raise MKUserError("event_p_host", _("Please specify a host name"))1071 rfc = mkeventd.send_event(event)1072 return None, "Test event generated and sent to Event Console.<br><pre>%s</pre>" % rfc1073def rule_pack_with_id(rule_packs, rule_pack_id):1074 for nr, entry in enumerate(rule_packs):1075 if entry["id"] == rule_pack_id:1076 return nr, entry1077 raise MKUserError(None, _("The requested rule pack does not exist."))1078def mode_mkeventd_rules(phase):1079 legacy_rules, rule_packs = load_mkeventd_rules()1080 rule_pack_id = html.var("rule_pack")1081 rule_pack_nr, rule_pack = rule_pack_with_id(rule_packs, rule_pack_id)1082 rules = rule_pack["rules"]1083 if phase == "title":1084 return _("Rule Package %s") % rule_pack["title"]1085 elif phase == "buttons":1086 mkeventd_rules_button()1087 mkeventd_changes_button()1088 if config.may("mkeventd.edit"):1089 html.context_button(_("New Rule"), html.makeuri_contextless([("mode", "mkeventd_edit_rule"), ("rule_pack", rule_pack_id)]), "new")1090 html.context_button(_("Properties"), html.makeuri_contextless([("mode", "mkeventd_edit_rule_pack"), ("edit", rule_pack_nr)]), "edit")1091 return1092 if phase == "action":1093 if html.var("_move_to"):1094 if html.check_transaction():1095 for move_nr, rule in enumerate(rules):1096 move_var = "_move_to_%s" % rule["id"]1097 if html.var(move_var):1098 other_pack_nr, other_pack = rule_pack_with_id(rule_packs, html.var(move_var))1099 other_pack["rules"][0:0] = [ rule ]1100 del rule_pack["rules"][move_nr]1101 save_mkeventd_rules(legacy_rules, rule_packs)1102 log_mkeventd("move-rule-to-pack", _("Moved rule %s to pack %s") % (rule["id"], other_pack["id"]))1103 return None, _("Moved rule %s to pack %s") % (rule["id"], html.attrencode(other_pack["title"]))1104 break1105 action_outcome = event_simulation_action()1106 if action_outcome:1107 return action_outcome1108 if html.has_var("_delete"):1109 nr = int(html.var("_delete"))1110 rule = rules[nr]1111 c = wato_confirm(_("Confirm rule deletion"),1112 _("Do you really want to delete the rule <b>%s</b> <i>%s</i>?" %1113 (rule["id"], rule.get("description",""))))1114 if c:1115 log_mkeventd("delete-rule", _("Deleted rule %s") % rules[nr]["id"])1116 del rules[nr]1117 save_mkeventd_rules(legacy_rules, rule_packs)1118 elif c == False:1119 return ""1120 else:1121 return1122 if html.check_transaction():1123 if html.has_var("_move"):1124 from_pos = int(html.var("_move"))1125 to_pos = int(html.var("_where"))1126 rule = rules[from_pos]1127 del rules[from_pos] # make to_pos now match!1128 rules[to_pos:to_pos] = [rule]1129 save_mkeventd_rules(legacy_rules, rule_packs)1130 log_mkeventd("move-rule", _("Changed position of rule %s") % rule["id"])1131 return1132 # Simulator1133 event = show_event_simulator()1134 if not rules:1135 html.message(_("This package does not yet contain any rules."))1136 else:1137 if len(rule_packs) > 1:1138 html.begin_form("move_to", method="POST")1139 # Show content of the rule package1140 table.begin(limit=None, sortable=False)1141 have_match = False1142 for nr, rule in enumerate(rules):1143 table.row()1144 delete_url = make_action_link([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id), ("_delete", nr)])1145 top_url = make_action_link([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id), ("_move", nr), ("_where", 0)])1146 bottom_url = make_action_link([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id), ("_move", nr), ("_where", len(rules)-1)])1147 up_url = make_action_link([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id), ("_move", nr), ("_where", nr-1)])1148 down_url = make_action_link([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id), ("_move", nr), ("_where", nr+1)])1149 edit_url = html.makeuri_contextless([("mode", "mkeventd_edit_rule"), ("rule_pack", rule_pack_id), ("edit", nr)])1150 clone_url = html.makeuri_contextless([("mode", "mkeventd_edit_rule"), ("rule_pack", rule_pack_id), ("clone", nr)])1151 table.cell(_("Actions"), css="buttons")1152 html.icon_button(edit_url, _("Edit this rule"), "edit")1153 html.icon_button(clone_url, _("Create a copy of this rule"), "clone")1154 html.icon_button(delete_url, _("Delete this rule"), "delete")1155 if not rule is rules[0]:1156 html.icon_button(top_url, _("Move this rule to the top"), "top")1157 html.icon_button(up_url, _("Move this rule one position up"), "up")1158 else:1159 html.empty_icon_button()1160 html.empty_icon_button()1161 if not rule is rules[-1]:1162 html.icon_button(down_url, _("Move this rule one position down"), "down")1163 html.icon_button(bottom_url, _("Move this rule to the bottom"), "bottom")1164 else:1165 html.empty_icon_button()1166 html.empty_icon_button()1167 table.cell("", css="buttons")1168 if rule.get("disabled"):1169 html.icon(_("This rule is currently disabled and will not be applied"), "disabled")1170 elif event:1171 result = mkeventd.event_rule_matches(rule, event)1172 if type(result) != tuple:1173 html.icon(_("Rule does not match: %s") % result, "rulenmatch")1174 else:1175 cancelling, groups = result1176 if have_match:1177 msg = _("This rule matches, but is overruled by a previous match.")1178 icon = "rulepmatch"1179 else:1180 if cancelling:1181 msg = _("This rule does a cancelling match.")1182 else:1183 msg = _("This rule matches.")1184 icon = "rulematch"1185 have_match = True1186 if groups:1187 msg += _(" Match groups: %s") % ",".join([ g or _('<None>') for g in groups ])1188 html.icon(msg, icon)1189 if rule.get("invert_matching"):1190 html.icon(_("Matching is inverted in this rule"), "inverted")1191 if rule.get("contact_groups") != None:1192 html.icon(_("This rule attaches contact group(s) to the events: %s") %1193 (", ".join(rule["contact_groups"]) or _("(none)")),1194 "contactgroups")1195 table.cell(_("ID"), '<a href="%s">%s</a>' % (edit_url, rule["id"]))1196 if rule.get("drop"):1197 table.cell(_("State"), css="state statep nowrap")1198 if rule["drop"] == "skip_pack":1199 html.write(_("SKIP PACK"))1200 else:1201 html.write(_("DROP"))1202 else:1203 if type(rule['state']) == tuple:1204 stateval = rule["state"][0]1205 else:1206 stateval = rule["state"]1207 txt = { 0: _("OK"), 1:_("WARN"),1208 2: _("CRIT"), 3:_("UNKNOWN"),1209 -1: _("(syslog)"),1210 'text_pattern':_("(set by message text)") }[stateval]1211 table.cell(_("State"), txt, css="state state%s" % stateval)1212 # Syslog priority1213 if "match_priority" in rule:1214 prio_from, prio_to = rule["match_priority"]1215 if prio_from == prio_to:1216 prio_text = mkeventd.syslog_priorities[prio_from][1]1217 else:1218 prio_text = mkeventd.syslog_priorities[prio_from][1][:2] + ".." + \1219 mkeventd.syslog_priorities[prio_to][1][:2]1220 else:1221 prio_text = ""1222 table.cell(_("Priority"), prio_text)1223 # Syslog Facility1224 table.cell(_("Facility"))1225 if "match_facility" in rule:1226 facnr = rule["match_facility"]1227 html.write("%s" % dict(mkeventd.syslog_facilities)[facnr])1228 table.cell(_("Service Level"),1229 dict(mkeventd.service_levels()).get(rule["sl"], rule["sl"]))1230 if defaults.omd_root:1231 hits = rule.get('hits')1232 table.cell(_("Hits"), hits != None and hits or '', css="number")1233 # Text to match1234 table.cell(_("Text to match"), rule.get("match"))1235 # Description1236 table.cell(_("Description"))1237 url = rule.get("docu_url")1238 if url:1239 html.icon_button(url, _("Context information about this rule"), "url", target="_blank")1240 html.write(" ")1241 html.write(html.attrencode(rule.get("description", "")))1242 # Move rule to other pack1243 if len(rule_packs) > 1:1244 table.cell(_("Move to pack..."))1245 choices = [ ("", "") ] + \1246 [ (pack["id"], pack["title"])1247 for pack in rule_packs1248 if not pack is rule_pack]1249 html.select("_move_to_%s" % rule["id"], choices, onchange="move_to.submit();")1250 if len(rule_packs) > 1:1251 html.hidden_field("_move_to", "yes")1252 html.hidden_fields()1253 html.end_form()1254 table.end()1255def copy_rules_from_master():1256 answer = mkeventd.query("REPLICATE 0")1257 if "rules" not in answer:1258 raise MKGeneralException(_("Cannot get rules from local event daemon."))1259 rule_packs = answer["rules"]1260 save_mkeventd_rules([], rule_packs)1261def mode_mkeventd_edit_rule_pack(phase):1262 legacy_rules, rule_packs = load_mkeventd_rules()1263 edit_nr = int(html.var("edit", -1)) # missing -> new rule pack1264 # Cloning currently not supported. Rule IDs wouldn't be unique!1265 # clone_nr = int(html.var("clone", -1)) # Only needed in 'new' mode1266 clone_nr = -11267 new = edit_nr < 01268 if phase == "title":1269 if new:1270 return _("Create new rule pack")1271 else:1272 try:1273 return _("Edit rule pack %s" % rule_packs[edit_nr]["id"])1274 except IndexError:1275 raise MKUserError("edit", _("The rule pack you are trying to "1276 "edit does not exist."))1277 elif phase == "buttons":1278 mkeventd_rules_button()1279 mkeventd_changes_button()1280 if edit_nr >= 0:1281 rule_pack_id = rule_packs[edit_nr]["id"]1282 html.context_button(_("Edit Rules"), html.makeuri([("mode", "mkeventd_rules"), ("rule_pack", rule_pack_id)]), "mkeventd_rules")1283 return1284 if new:1285 ### if clone_nr >= 0:1286 ### rule_pack = {}1287 ### rule_pack.update(rule_packs[clone_nr])1288 ### else:1289 rule_pack = { "rules" : [], }1290 else:1291 rule_pack = rule_packs[edit_nr]1292 if phase == "action":1293 if not html.check_transaction():1294 return "mkeventd_rule_packs"1295 if not new: # or clone_nr >= 0:1296 existing_rules = rule_pack["rules"]1297 else:1298 existing_rules = []1299 rule_pack = vs_mkeventd_rule_pack.from_html_vars("rule_pack")1300 vs_mkeventd_rule_pack.validate_value(rule_pack, "rule_pack")1301 rule_pack["rules"] = existing_rules1302 new_id = rule_pack["id"]1303 # Make sure that ID is unique1304 for nr, other_rule_pack in enumerate(rule_packs):1305 if new or nr != edit_nr:1306 if other_rule_pack["id"] == new_id:1307 raise MKUserError("rule_pack_p_id", _("A rule pack with this ID already exists."))1308 if new:1309 rule_packs = [ rule_pack ] + rule_packs1310 else:1311 rule_packs[edit_nr] = rule_pack1312 save_mkeventd_rules(legacy_rules, rule_packs)1313 if new:1314 log_mkeventd("new-rule-pack", _("Created new rule pack with id %s" % rule_pack["id"]))1315 else:1316 log_mkeventd("edit-rule-pack", _("Modified rule pack %s" % rule_pack["id"]))1317 return "mkeventd_rule_packs"1318 html.begin_form("rule_pack")1319 vs_mkeventd_rule_pack.render_input("rule_pack", rule_pack)1320 vs_mkeventd_rule_pack.set_focus("rule_pack")1321 html.button("save", _("Save"))1322 html.hidden_fields()1323 html.end_form()1324def mode_mkeventd_edit_rule(phase):1325 legacy_rules, rule_packs = load_mkeventd_rules()1326 if html.has_var("rule_pack"):1327 rule_pack_nr, rule_pack = rule_pack_with_id(rule_packs, html.var("rule_pack"))1328 else:1329 # In links from multisite views the rule pack is not known.1330 # We just know the rule id and need to find the pack ourselves.1331 rule_id = html.var("rule_id")1332 if rule_id == None:1333 raise MKUserError("rule_id", _("The rule you are trying to edit does not exist."))1334 rule_pack = None1335 for nr, pack in enumerate(rule_packs):1336 for rnr, rule in enumerate(pack["rules"]):1337 if rule_id == rule["id"]:1338 rule_pack_nr = nr1339 rule_pack = pack1340 html.set_var("edit", str(rnr))1341 html.set_var("rule_pack", pack["id"])1342 break1343 if not rule_pack:1344 raise MKUserError("rule_id", _("The rule you are trying to edit does not exist."))1345 rules = rule_pack["rules"]1346 edit_nr = int(html.var("edit", -1)) # missing -> new rule1347 clone_nr = int(html.var("clone", -1)) # Only needed in 'new' mode1348 new = edit_nr < 01349 if phase == "title":1350 if new:1351 return _("Create new rule")1352 else:1353 try:1354 return _("Edit rule %s" % rules[edit_nr]["id"])1355 except IndexError:1356 raise MKUserError("edit", _("The rule you are trying to edit does not exist."))1357 elif phase == "buttons":1358 home_button()1359 mkeventd_rules_button()1360 mkeventd_changes_button()1361 if clone_nr >= 0:1362 html.context_button(_("Clear Rule"), html.makeuri([("_clear", "1")]), "clear")1363 return1364 if new:1365 if clone_nr >= 0 and not html.var("_clear"):1366 rule = {}1367 rule.update(rules[clone_nr])1368 else:1369 rule = {}1370 else:1371 rule = rules[edit_nr]1372 if phase == "action":1373 if not html.check_transaction():1374 return "mkeventd_rules"1375 if not new:1376 old_id = rule["id"]1377 rule = vs_mkeventd_rule.from_html_vars("rule")1378 vs_mkeventd_rule.validate_value(rule, "rule")1379 if not new and old_id != rule["id"]:1380 raise MKUserError("rule_p_id",1381 _("It is not allowed to change the ID of an existing rule."))1382 elif new:1383 for pack in rule_packs:1384 for r in pack["rules"]:1385 if r["id"] == rule["id"]:1386 raise MKUserError("rule_p_id", _("A rule with this ID already exists in rule pack <b>%s</b>.") % html.attrencode(pack["title"]))1387 try:1388 num_groups = re.compile(rule["match"]).groups1389 except:1390 raise MKUserError("rule_p_match",1391 _("Invalid regular expression"))1392 if num_groups > 9:1393 raise MKUserError("rule_p_match",1394 _("You matching text has too many regular expresssion subgroups. "1395 "Only nine are allowed."))1396 if "count" in rule and "expect" in rule:1397 raise MKUserError("rule_p_expect_USE", _("You cannot use counting and expecting "1398 "at the same time in the same rule."))1399 if "expect" in rule and "delay" in rule:1400 raise MKUserError("rule_p_expect_USE", _("You cannot use expecting and delay "1401 "at the same time in the same rule, sorry."))1402 # Make sure that number of group replacements do not exceed number1403 # of groups in regex of match1404 num_repl = 91405 while num_repl > num_groups:1406 repl = "\\%d" % num_repl1407 for name, value in rule.items():1408 if name.startswith("set_") and type(value) in [ str, unicode ]:1409 if repl in value:1410 raise MKUserError("rule_p_" + name,1411 _("You are using the replacment reference <tt>\%d</tt>, "1412 "but your match text has only %d subgroups." % (1413 num_repl, num_groups)))1414 num_repl -= 11415 if new and clone_nr >= 0:1416 rules[clone_nr:clone_nr] = [ rule ]1417 elif new:1418 rules[0:0] = [ rule ]1419 else:1420 rules[edit_nr] = rule1421 save_mkeventd_rules(legacy_rules, rule_packs)1422 if new:1423 log_mkeventd("new-rule", _("Created new event correlation rule with id %s" % rule["id"]))1424 else:1425 log_mkeventd("edit-rule", _("Modified event correlation rule %s" % rule["id"]))1426 # Reset hit counters of this rule1427 mkeventd.query("COMMAND RESETCOUNTERS;" + rule["id"])1428 return "mkeventd_rules"1429 html.begin_form("rule")1430 vs_mkeventd_rule.render_input("rule", rule)1431 vs_mkeventd_rule.set_focus("rule")1432 html.button("save", _("Save"))1433 html.hidden_fields()1434 html.end_form()1435# This hook is executed when one applies the pending configuration changes1436# related to the mkeventd via WATO on the local system. The hook is called1437# without parameters.1438def call_hook_mkeventd_activate_changes():1439 if hooks.registered('mkeventd-activate-changes'):1440 hooks.call("mkeventd-activate-changes")1441def mode_mkeventd_changes(phase):1442 if phase == "title":1443 return _("Event Console - Pending Changes")1444 elif phase == "buttons":1445 home_button()1446 mkeventd_rules_button()1447 if config.may("mkeventd.activate") and parse_audit_log("mkeventd") and mkeventd.daemon_running():1448 html.context_button(_("Reload Config!"),1449 html.makeactionuri([("_activate", "now")]), "apply", hot=True)1450 mkeventd_config_button()1451 mkeventd_mibs_button()1452 elif phase == "action":1453 if html.check_transaction():1454 mkeventd_reload()1455 call_hook_mkeventd_activate_changes()1456 return "mkeventd_rule_packs", _("The new configuration has successfully been activated.")1457 else:1458 if not mkeventd.daemon_running():1459 warning = _("The Event Console Daemon is currently not running. ")1460 if defaults.omd_root:1461 warning += _("Please make sure that you have activated it with <tt>omd config set MKEVENTD on</tt> "1462 "before starting this site.")1463 html.show_warning(warning)1464 entries = parse_audit_log("mkeventd")1465 if entries:1466 render_audit_log(entries, "pending", hilite_others=True)1467 else:1468 html.write("<div class=info>" + _("There are no pending changes.") + "</div>")1469def log_mkeventd(what, message):1470 log_entry(None, what, message, "audit.log") # central WATO audit log1471 log_entry(None, what, message, "mkeventd.log") # pending changes for mkeventd1472 # Mark all sites as "need sync" that have opted for EC replication1473 at_least_one = False1474 if is_distributed():1475 for site_id, site in config.sites.items():1476 if site.get("replicate_ec") and not config.site_is_local(site_id):1477 update_replication_status(site_id, { "need_sync" : True })1478 remove_sync_snapshot(site_id)1479 at_least_one = True1480 if at_least_one:1481 log_entry(None, what, message, "pending.log")1482def mkeventd_changes_button():1483 pending = parse_audit_log("mkeventd")1484 if len(pending) > 0:1485 buttontext = "%d " % len(pending) + _("EC-Changes")1486 hot = True1487 icon = "mkeventd"1488 else:1489 buttontext = _("No EC-Changes")1490 hot = False1491 icon = "mkeventd"1492 html.context_button(buttontext, html.makeuri_contextless([("mode", "mkeventd_changes")]), icon, hot)1493def mkeventd_rules_button():1494 html.context_button(_("Rule Packs"), html.makeuri_contextless([("mode", "mkeventd_rule_packs")]), "back")1495def mkeventd_config_button():1496 if config.may("mkeventd.config"):1497 html.context_button(_("Settings"), html.makeuri_contextless([("mode", "mkeventd_config")]), "configuration")1498def mkeventd_status_button():1499 html.context_button(_("Server Status"), html.makeuri_contextless([("mode", "mkeventd_status")]), "status")1500def mkeventd_mibs_button():1501 html.context_button(_("SNMP MIBs"), html.makeuri_contextless([("mode", "mkeventd_mibs")]), "snmpmib")1502def mode_mkeventd_status(phase):1503 if phase == "title":1504 return _("Event Console - Server Status")1505 elif phase == "buttons":1506 home_button()1507 mkeventd_rules_button()1508 mkeventd_config_button()1509 mkeventd_mibs_button()1510 return1511 elif phase == "action":1512 if config.may("mkeventd.switchmode"):1513 if html.has_var("_switch_sync"):1514 new_mode = "sync"1515 else:1516 new_mode = "takeover"1517 c = wato_confirm(_("Confirm switching replication mode"),1518 _("Do you really want to switch the event daemon to %s mode?" %1519 new_mode))1520 if c:1521 mkeventd.query("COMMAND SWITCHMODE;%s" % new_mode)1522 log_audit(None, "mkeventd-switchmode", _("Switched replication slave mode to %s" % new_mode))1523 return None, _("Switched to %s mode") % new_mode1524 elif c == False:1525 return ""1526 else:1527 return1528 return1529 if not mkeventd.daemon_running():1530 warning = _("The Event Console Daemon is currently not running. ")1531 if defaults.omd_root:1532 warning += _("Please make sure that you have activated it with <tt>omd config set MKEVENTD on</tt> "1533 "before starting this site.")1534 html.show_warning(warning)1535 return1536 response = mkeventd.query("GET status")1537 status = dict(zip(response[0], response[1]))1538 repl_mode = status["status_replication_slavemode"]1539 html.write("<h3>%s</h3>" % _("Current Server Status"))1540 html.write("<ul>")1541 html.write("<li>%s</li>" % _("Event Daemon is running."))1542 html.write("<li>%s: <b>%s</b></li>" % (_("Current replication mode"),1543 { "sync" : _("synchronize"),1544 "takeover" : _("Takeover!"),1545 }.get(repl_mode, _("master / standalone"))))1546 if repl_mode in [ "sync", "takeover" ]:1547 html.write(("<li>" + _("Status of last synchronization: <b>%s</b>") + "</li>") % (1548 status["status_replication_success"] and _("Success") or _("Failed!")))1549 last_sync = status["status_replication_last_sync"]1550 if last_sync:1551 html.write("<li>" + _("Last successful sync %d seconds ago.") % (time.time() - last_sync) + "</li>")1552 else:1553 html.write(_("<li>No successful synchronization so far.</li>"))1554 html.write("</ul>")1555 if config.may("mkeventd.switchmode"):1556 html.begin_form("switch")1557 if repl_mode == "sync":1558 html.button("_switch_takeover", _("Switch to Takeover mode!"))1559 elif repl_mode == "takeover":1560 html.button("_switch_sync", _("Switch back to sync mode!"))1561 html.hidden_fields()1562 html.end_form()1563def mode_mkeventd_config(phase):1564 if phase == 'title':1565 return _('Event Console Configuration')1566 elif phase == 'buttons':1567 home_button()1568 mkeventd_rules_button()1569 mkeventd_changes_button()1570 html.context_button(_("Server Status"), html.makeuri_contextless([("mode", "mkeventd_status")]), "status")1571 return1572 vs = [ (v[1], v[2]) for v in configvar_groups()[_("Event Console")] ]1573 current_settings = load_configuration_settings()1574 pending_func = configvar_domains()['mkeventd']['pending']1575 if phase == "action":1576 varname = html.var("_varname")1577 action = html.var("_action")1578 if not varname:1579 return1580 domain, valuespec, need_restart, allow_reset, in_global_settings = configvars()[varname]1581 def_value = valuespec.default_value()1582 if action == "reset" and not isinstance(valuespec, Checkbox):1583 c = wato_confirm(1584 _("Resetting configuration variable"),1585 _("Do you really want to reset the configuration variable <b>%s</b> "1586 "back to the default value of <b><tt>%s</tt></b>?") %1587 (varname, valuespec.value_to_text(def_value)))1588 else:1589 if not html.check_transaction():1590 return1591 c = True # no confirmation for direct toggle1592 if c:1593 if varname in current_settings:1594 current_settings[varname] = not current_settings[varname]1595 else:1596 current_settings[varname] = not def_value1597 msg = _("Changed Configuration variable %s to %s." % (varname,1598 current_settings[varname] and "on" or "off"))1599 save_configuration_settings(current_settings)1600 pending_func(msg)1601 if action == "_reset":1602 return "mkeventd_config", msg1603 else:1604 return "mkeventd_config"1605 elif c == False:1606 return ""1607 else:1608 return None1609 html.write('<div class=globalvars>')1610 forms.header(_('Event Console Settings'))1611 for (varname, valuespec) in vs:1612 defaultvalue = valuespec.default_value()1613 value = current_settings.get(varname, valuespec.default_value())1614 edit_url = html.makeuri_contextless([("mode", "mkeventd_edit_configvar"),1615 ("varname", varname), ("site", html.var("site", ""))])1616 help_text = type(valuespec.help()) == unicode and valuespec.help().encode("utf-8") or valuespec.help() or ''1617 title_text = type(valuespec.title()) == unicode and valuespec.title().encode("utf-8") or valuespec.title()1618 title = '<a href="%s" class=%s title="%s">%s</a>' % \1619 (edit_url, varname in current_settings and "modified" or "",1620 html.strip_tags(help_text), title_text)1621 to_text = valuespec.value_to_text(value)1622 # Is this a simple (single) value or not? change styling in these cases...1623 simple = True1624 if '\n' in to_text or '<td>' in to_text:1625 simple = False1626 forms.section(title, simple=simple)1627 if isinstance(valuespec, Checkbox):1628 toggle_url = html.makeactionuri([("_action", "toggle"), ("_varname", varname)])1629 toggle_value = current_settings.get(varname, defaultvalue)1630 html.icon_button(toggle_url, _("Immediately toggle this setting"),1631 "snapin_switch_" + (toggle_value and "on" or "off"))1632 else:1633 html.write('<a href="%s">%s</a>' % (edit_url, to_text))1634 forms.end()1635 html.write('</div>')1636def mode_mkeventd_mibs(phase):1637 if phase == 'title':1638 return _('SNMP MIBs for Trap Translation')1639 elif phase == 'buttons':1640 home_button()1641 mkeventd_rules_button()1642 mkeventd_changes_button()1643 mkeventd_status_button()1644 mkeventd_config_button()1645 return1646 elif phase == 'action':1647 if html.has_var("_delete"):1648 filename = html.var("_delete")1649 mibs = load_snmp_mibs(mkeventd.mib_upload_dir)1650 if filename in mibs:1651 c = wato_confirm(_("Confirm MIB deletion"),1652 _("Do you really want to delete the MIB file <b>%s</b>?" % filename))1653 if c:1654 log_mkeventd("delete-mib", _("Deleted MIB %s") % filename)1655 # Delete the uploaded mib file1656 os.remove(mkeventd.mib_upload_dir + "/" + filename)1657 # Also delete the compiled files1658 mib_name = mibs[filename]["name"]1659 for f in [ mkeventd.compiled_mibs_dir + "/" + mib_name + ".py",1660 mkeventd.compiled_mibs_dir + "/" + mib_name + ".pyc",1661 mkeventd.compiled_mibs_dir + "/" + filename.rsplit('.', 1)[0].upper() + ".py",1662 mkeventd.compiled_mibs_dir + "/" + filename.rsplit('.', 1)[0].upper() + ".pyc"1663 ]:1664 if os.path.exists(f):1665 os.remove(f)1666 elif c == False:1667 return ""1668 else:1669 return1670 elif "_upload_mib" in html.uploads:1671 uploaded_mib = html.uploaded_file("_upload_mib")1672 filename, mimetype, content = uploaded_mib1673 if filename:1674 try:1675 msg = upload_mib(filename, mimetype, content)1676 return None, msg1677 except Exception, e:1678 if config.debug:1679 raise1680 else:1681 raise MKUserError("_upload_mib", str(e))1682 return1683 html.write("<h3>" + _("Upload MIB file") + "</h3>")1684 html.write(_("Use this form to upload MIB files for translating incoming SNMP traps. "1685 "You can upload single MIB files with the extension <tt>.mib</tt> or "1686 "<tt>.txt</tt>, but you can also upload multiple MIB files at once by "1687 "packing them into a <tt>.zip</tt> file. Only files in the root directory "1688 "of the zip file will be processed.<br><br>"))1689 html.begin_form("upload_form", method = "POST")1690 forms.header(_("Upload MIB file"))1691 forms.section(_("Select file"))1692 html.upload_file("_upload_mib")1693 forms.end()1694 html.button("upload_button", _("Upload MIB(s)"), "submit")1695 html.hidden_fields()1696 html.end_form()1697 if not os.path.exists(mkeventd.mib_upload_dir):1698 os.makedirs(mkeventd.mib_upload_dir) # Let exception happen if this fails. Never happens on OMD1699 for path, title in mkeventd.mib_dirs:1700 table.begin("mibs_"+path, title)1701 for filename, mib in sorted(load_snmp_mibs(path).items()):1702 table.row()1703 table.cell(_("Actions"), css="buttons")1704 if path == mkeventd.mib_upload_dir:1705 delete_url = make_action_link([("mode", "mkeventd_mibs"), ("_delete", filename)])1706 html.icon_button(delete_url, _("Delete this MIB"), "delete")1707 table.cell(_("Filename"), filename)1708 table.cell(_("MIB"), mib.get("name", ""))1709 table.cell(_("Organization"), mib.get("organization", ""))1710 table.cell(_("Size"), bytes_human_readable(mib.get("size", 0)), css="number")1711 table.end()1712def load_snmp_mibs(path):1713 found = {}1714 try:1715 file_names = os.listdir(path)1716 except OSError, e:1717 if e.errno == 2: # not existing directories are ok1718 return found1719 else:1720 raise1721 for fn in file_names:1722 if fn[0] != '.':1723 mib = parse_snmp_mib_header(path + "/" + fn)1724 found[fn] = mib1725 return found1726def parse_snmp_mib_header(path):1727 mib = {}1728 mib["size"] = os.stat(path).st_size1729 # read till first "OBJECT IDENTIFIER" declaration1730 head = ''1731 for line in file(path):1732 if not line.startswith("--"):1733 if 'OBJECT IDENTIFIER' in line:1734 break # seems the header is finished1735 head += line1736 # now try to extract some relevant information from the header1737 matches = re.search('ORGANIZATION[^"]+"([^"]+)"', head, re.M)1738 if matches:1739 mib['organization'] = matches.group(1)1740 matches = re.search('^\s*([A-Z0-9][A-Z0-9-]+)\s', head, re.I | re.M)1741 if matches:1742 mib['name'] = matches.group(1)1743 return mib1744def validate_and_compile_mib(mibname, content):1745 try:1746 from pysmi.compiler import MibCompiler1747 from pysmi.parser.smiv1compat import SmiV1CompatParser1748 from pysmi.searcher.pypackage import PyPackageSearcher1749 from pysmi.searcher.pyfile import PyFileSearcher1750 from pysmi.writer.pyfile import PyFileWriter1751 from pysmi.reader.localfile import FileReader1752 from pysmi.codegen.pysnmp import PySnmpCodeGen, baseMibs, defaultMibPackages1753 from pysmi.writer.callback import CallbackWriter1754 from pysmi.reader.callback import CallbackReader1755 from pysmi.searcher.stub import StubSearcher1756 from pysmi.error import PySmiError1757 except ImportError, e:1758 raise Exception(_('You are missing the needed pysmi python module (%s).') % e)1759 make_nagios_directory(mkeventd.compiled_mibs_dir)1760 # This object manages the compilation of the uploaded SNMP mib1761 # but also resolving dependencies and compiling dependents1762 compiler = MibCompiler(SmiV1CompatParser(),1763 PySnmpCodeGen(),1764 PyFileWriter(mkeventd.compiled_mibs_dir))1765 # Provides the just uploaded MIB module1766 compiler.addSources(1767 CallbackReader(lambda m,c: m==mibname and c or '', content)1768 )1769 # Directories containing ASN1 MIB files which may be used for1770 # dependency resolution1771 compiler.addSources(*[ FileReader(path) for path, title in mkeventd.mib_dirs ])1772 # check for already compiled MIBs1773 compiler.addSearchers(PyFileSearcher(mkeventd.compiled_mibs_dir))1774 # and also check PySNMP shipped compiled MIBs1775 compiler.addSearchers(*[ PyPackageSearcher(x) for x in defaultMibPackages ])1776 # never recompile MIBs with MACROs1777 compiler.addSearchers(StubSearcher(*baseMibs))1778 try:1779 if not content.strip():1780 raise Exception(_("The file is empty"))1781 results = compiler.compile(mibname, ignoreErrors=True, genTexts=True)1782 errors = []1783 for name, state_obj in sorted(results.items()):1784 if mibname == name and state_obj == 'failed':1785 raise Exception(_('Failed to compile your module: %s') % state_obj.error)1786 if state_obj == 'missing':1787 errors.append(_('%s - Dependency missing') % name)1788 elif state_obj == 'failed':1789 errors.append(_('%s - Failed to compile (%s)') % (name, state_obj.error))1790 msg = _("MIB file %s uploaded.") % mibname1791 if errors:1792 msg += '<br>'+_('But there were errors:')+'<br>'1793 msg += '<br>\n'.join(errors)1794 return msg1795 except PySmiError, e:1796 if config.debug:1797 raise e1798 raise Exception(_('Failed to process your MIB file (%s): %s') % (mibname, e))1799def upload_mib(filename, mimetype, content):1800 validate_mib_file_name(filename)1801 if is_zipfile(cStringIO.StringIO(content)):1802 msg = process_uploaded_zip_file(filename, content)1803 else:1804 if mimetype == "application/tar" or filename.lower().endswith(".gz") or filename.lower().endswith(".tgz"):1805 raise Exception(_("Sorry, uploading TAR/GZ files is not yet implemented."))1806 msg = process_uploaded_mib_file(filename, content)1807 return msg1808def process_uploaded_zip_file(filename, content):1809 zip_obj = zipfile.ZipFile(cStringIO.StringIO(content))1810 messages = []1811 for entry in zip_obj.infolist():1812 success, fail = 0, 01813 try:1814 mib_file_name = entry.filename1815 if mib_file_name[-1] == "/":1816 continue # silently skip directories1817 validate_mib_file_name(mib_file_name)1818 mib_obj = zip_obj.open(mib_file_name)1819 messages.append(process_uploaded_mib_file(mib_file_name, mib_obj.read()))1820 success += 11821 except Exception, e:1822 messages.append(_("Skipped %s: %s") % (html.attrencode(mib_file_name), e))1823 fail += 11824 return "<br>\n".join(messages) + \1825 "<br><br>\nProcessed %d MIB files, skipped %d MIB files" % (success, fail)1826# Used zipfile.is_zipfile(cStringIO.StringIO(content)) before, but this only1827# possible with python 2.7. zipfile is only supporting checking of files by1828# their path.1829def is_zipfile(fo):1830 try:1831 zipfile.ZipFile(fo)1832 return True1833 except zipfile.BadZipfile:1834 return False1835def validate_mib_file_name(filename):1836 if filename.startswith(".") or "/" in filename:1837 raise Exception(_("Invalid filename"))1838def process_uploaded_mib_file(filename, content):1839 if '.' in filename:1840 mibname = filename.split('.')[0]1841 else:1842 mibname = filename1843 msg = validate_and_compile_mib(mibname.upper(), content)1844 file(mkeventd.mib_upload_dir + "/" + filename, "w").write(content)1845 log_mkeventd("uploaded-mib", _("MIB %s: %s") % (filename, msg))1846 return msg1847if mkeventd_enabled:1848 modes["mkeventd_rule_packs"] = (["mkeventd.edit"], mode_mkeventd_rule_packs)1849 modes["mkeventd_rules"] = (["mkeventd.edit"], mode_mkeventd_rules)1850 modes["mkeventd_edit_rule"] = (["mkeventd.edit"], mode_mkeventd_edit_rule)1851 modes["mkeventd_edit_rule_pack"] = (["mkeventd.edit"], mode_mkeventd_edit_rule_pack)1852 modes["mkeventd_changes"] = (["mkeventd.edit"], mode_mkeventd_changes)1853 modes["mkeventd_status"] = ([], mode_mkeventd_status)1854 modes["mkeventd_config"] = (['mkeventd.config'], mode_mkeventd_config)1855 modes["mkeventd_edit_configvar"] = (['mkeventd.config'], lambda p: mode_edit_configvar(p, 'mkeventd'))1856 modes["mkeventd_mibs"] = (['mkeventd.config'], mode_mkeventd_mibs)1857#.1858# .--Permissions---------------------------------------------------------.1859# | ____ _ _ |1860# | | _ \ ___ _ __ _ __ ___ (_)___ ___(_) ___ _ __ ___ |1861# | | |_) / _ \ '__| '_ ` _ \| / __/ __| |/ _ \| '_ \/ __| |1862# | | __/ __/ | | | | | | | \__ \__ \ | (_) | | | \__ \ |1863# | |_| \___|_| |_| |_| |_|_|___/___/_|\___/|_| |_|___/ |1864# | |1865# +----------------------------------------------------------------------+1866# | Declaration of Event Console specific permissions for Multisite |1867# '----------------------------------------------------------------------'1868if mkeventd_enabled:1869 config.declare_permission_section("mkeventd", _("Event Console"))1870 config.declare_permission("mkeventd.config",1871 _("Configuration of Event Console "),1872 _("This permission allows to configure the global settings "1873 "of the event console."),1874 ["admin"])1875 config.declare_permission("mkeventd.edit",1876 _("Configuration of event rules"),1877 _("This permission allows the creation, modification and "1878 "deletion of event correlation rules."),1879 ["admin"])1880 config.declare_permission("mkeventd.activate",1881 _("Activate changes for event console"),1882 _("Activation of changes for the event console (rule modification, "1883 "global settings) is done separately from the monitoring configuration "1884 "and needs this permission."),1885 ["admin"])1886 config.declare_permission("mkeventd.switchmode",1887 _("Switch slave replication mode"),1888 _("This permission is only useful if the Event Console is setup as a replication "1889 "slave. It allows a manual switch between sync and takeover mode."),1890 ["admin"])1891 modules.append(1892 ( "mkeventd_rule_packs", _("Event Console"), "mkeventd", "mkeventd.edit",1893 _("Manage event classification and correlation rules for the "1894 "Event Console")))1895#.1896# .--Settings & Rules----------------------------------------------------.1897# | ____ _ _ _ ____ _ |1898# |/ ___| ___| |_| |_(_)_ __ __ _ ___ _ | _ \ _ _| | ___ ___ |1899# |\___ \ / _ \ __| __| | '_ \ / _` / __|_| |_| |_) | | | | |/ _ \/ __| |1900# | ___) | __/ |_| |_| | | | | (_| \__ \_ _| _ <| |_| | | __/\__ \ |1901# ||____/ \___|\__|\__|_|_| |_|\__, |___/ |_| |_| \_\\__,_|_|\___||___/ |1902# | |___/ |1903# +----------------------------------------------------------------------+1904# | Declarations for global settings of EC parameters and of a rule for |1905# | active checks that query the EC status of a host. |1906# '----------------------------------------------------------------------'1907if mkeventd_enabled:1908 register_configvar_domain("mkeventd", mkeventd_config_dir,1909 pending = lambda msg: log_mkeventd('config-change', msg), in_global_settings = False)1910 group = _("Event Console")1911 configvar_order()[group] = 181912 register_configvar(group,1913 "remote_status",1914 Optional(1915 Tuple(1916 elements = [1917 Integer(1918 title = _("Port number:"),1919 help = _("If you are running the Event Console as a non-root (such as in an OMD site) "1920 "please choose port number greater than 1024."),1921 minvalue = 1,1922 maxvalue = 65535,1923 default_value = 6558,1924 ),1925 Checkbox(1926 title = _("Security"),1927 label = _("allow execution of commands and actions via TCP"),1928 help = _("Without this option the access is limited to querying the current "1929 "and historic event status."),1930 default_value = False,1931 true_label = _("allow commands"),1932 false_label = _("no commands"),1933 ),1934 Optional(1935 ListOfStrings(1936 help = _("The access to the event status via TCP will only be allowed from "1937 "this source IP addresses"),1938 valuespec = IPv4Address(),1939 orientation = "horizontal",1940 allow_empty = False,1941 ),1942 label = _("Restrict access to the following source IP addresses"),1943 none_label = _("access unrestricted"),1944 )1945 ],1946 ),1947 title = _("Access to event status via TCP"),1948 help = _("In Multisite setups if you want <a href=\"%s\">event status checks</a> for hosts that "1949 "live on a remote site you need to activate remote access to the event status socket "1950 "via TCP. This allows to query the current event status via TCP. If you do not restrict "1951 "this to queries also event actions are possible from remote. This feature is not used "1952 "by the event status checks nor by Multisite so we propose not allowing commands via TCP.") % \1953 "wato.py?mode=edit_ruleset&varname=active_checks%3Amkevents",1954 none_label = _("no access via TCP"),1955 ),1956 domain = "mkeventd",1957 )1958 register_configvar(group,1959 "replication",1960 Optional(1961 Dictionary(1962 optional_keys = [ "takeover", "fallback", "disabled", "logging" ],1963 elements = [1964 ( "master",1965 Tuple(1966 title = _("Master Event Console"),1967 help = _("Specify the host name or IP address of the master Event Console that "1968 "you want to replicate from. The port number must be the same as set "1969 "in the master in <i>Access to event status via TCP</i>."),1970 elements = [1971 TextAscii(1972 title = _("Hostname/IP address of Master Event Console:"),1973 allow_empty = False,1974 attrencode = True,1975 ),1976 Integer(1977 title = _("TCP Port number of status socket:"),1978 minvalue = 1,1979 maxvalue = 65535,1980 default_value = 6558,1981 ),1982 ],1983 )1984 ),1985 ( "interval",1986 Integer(1987 title = _("Replication interval"),1988 help = _("The replication will be triggered each this number of seconds"),1989 label = _("Do a replication every"),1990 unit = _("sec"),1991 minvalue = 1,1992 default_value = 10,1993 ),1994 ),1995 ( "connect_timeout",1996 Integer(1997 title = _("Connect Timeout"),1998 help = _("TCP connect timeout for connecting to the master"),1999 label = _("Try bringing up TCP connection for"),2000 unit = _("sec"),2001 minvalue = 1,2002 default_value = 10,2003 ),2004 ),2005 ( "takeover",2006 Integer(2007 title = _("Automatic takeover"),2008 help = _("If you enable this option then the slave will automatically "2009 "takeover and enable event processing if the master is for "2010 "the configured number of seconds unreachable."),2011 label = _("Takeover after a master downtime of"),2012 unit = _("sec"),2013 minvalue = 1,2014 default_value = 30,2015 ),2016 ),2017 ( "fallback",2018 Integer(2019 title = _("Automatic fallback"),2020 help = _("If you enable this option then the slave will automatically "2021 "fallback from takeover mode to slavemode if the master is "2022 "rechable again within the selected number of seconds since "2023 "the previous unreachability (not since the takeover)"),2024 label = _("Fallback if master comes back within"),2025 unit = _("sec"),2026 minvalue = 1,2027 default_value = 60,2028 ),2029 ),2030 ( "disabled",2031 FixedValue(2032 True,2033 totext = _("Replication is disabled"),2034 title = _("Currently disable replication"),2035 help = _("This allows you to disable the replication without loosing "2036 "your settings. If you check this box, then no replication "2037 "will be done and the Event Console will act as its own master."),2038 ),2039 ),2040 ( "logging",2041 FixedValue(2042 True,2043 title = _("Log replication events"),2044 totext = _("logging is enabled"),2045 help = _("Enabling this option will create detailed log entries for all "2046 "replication activities of the slave. If disabled only problems "2047 "will be logged."),2048 ),2049 ),2050 ]2051 ),2052 title = _("Enable replication from a master"),2053 ),2054 domain = "mkeventd",2055 )2056 register_configvar(group,2057 "retention_interval",2058 Age(title = _("State Retention Interval"),2059 help = _("In this interval the event daemon will save its state "2060 "to disk, so that you won't lose your current event "2061 "state in case of a crash."),2062 default_value = 60,2063 ),2064 domain = "mkeventd",2065 )2066 register_configvar(group,2067 "housekeeping_interval",2068 Age(title = _("Housekeeping Interval"),2069 help = _("From time to time the eventd checks for messages that are expected to "2070 "be seen on a regular base, for events that time out and yet for "2071 "count periods that elapse. Here you can specify the regular interval "2072 "for that job."),2073 default_value = 60,2074 ),2075 domain = "mkeventd",2076 )2077 register_configvar(group,2078 "statistics_interval",2079 Age(title = _("Statistics Interval"),2080 help = _("The event daemon keeps statistics about the rate of messages, events "2081 "rule hits, and other stuff. These values are updated in the interval "2082 "configured here and are available in the sidebar snapin <i>Event Console "2083 "Performance</i>"),2084 default_value = 5,2085 ),2086 domain = "mkeventd",2087 )2088 register_configvar(group,2089 "debug_rules",2090 Checkbox(title = _("Debug rule execution"),2091 label = _("enable extensive rule logging"),2092 help = _("This option turns on logging the execution of rules. For each message received "2093 "the execution details of each rule are logged. This creates an immense "2094 "volume of logging and should never be used in productive operation."),2095 default_value = False),2096 domain = "mkeventd",2097 )2098 register_configvar(group,2099 "log_messages",2100 Checkbox(title = _("Syslog-like message logging"),2101 label = _("Log all messages into syslog-like logfiles"),2102 help = _("When this option is enabled, then <b>every</b> incoming message is being "2103 "logged into the directory <tt>messages</tt> in the Event Consoles state "2104 "directory. The logfile rotation is analog to that of the history logfiles. "2105 "Please note that if you have lots of incoming messages then these "2106 "files can get very large."),2107 default_value = False),2108 domain = "mkeventd",2109 )2110 register_configvar(group,2111 "rule_optimizer",2112 Checkbox(title = _("Optimize rule execution"),2113 label = _("enable optimized rule execution"),2114 help = _("This option turns on a faster algorithm for matching events to rules. "),2115 default_value = True),2116 domain = "mkeventd",2117 )2118 register_configvar(group,2119 "log_level",2120 DropdownChoice(2121 title = _("Log level"),2122 help = _("You can configure the Event Console to log more details about it's actions. "2123 "These information are logged into the file <tt>%s</tt>") %2124 site_neutral_path(defaults.log_dir + "/mkeventd.log"),2125 choices = [2126 (0, _("Normal logging")),2127 (1, _("Verbose logging")),2128 ],2129 default_value = 0,2130 ),2131 domain = "mkeventd",2132 )2133 register_configvar(group,2134 "log_rulehits",2135 Checkbox(title = _("Log rule hits"),2136 label = _("Log hits for rules in log of Event Console"),2137 help = _("If you enable this option then every time an event matches a rule "2138 "(by normal hit, cancelling, counting or dropping) a log entry will be written "2139 "into the log file of the Event Console. Please be aware that this might lead to "2140 "a large number of log entries. "),2141 default_value = False),2142 domain = "mkeventd",2143 )2144 register_configvar(group,2145 "debug_mkeventd_queries",2146 Checkbox(title = _("Debug queries to Event Console"),2147 label = _("Enable debugging of queries"),2148 help = _("With this option turned on all queries asking for data of the Event Console "2149 "will be displayed in the views."),2150 default_value = False),2151 domain = "mkeventd",2152 )2153 register_configvar(group,2154 "actions",2155 vs_mkeventd_actions,2156 allow_reset = False,2157 domain = "mkeventd",2158 )2159 register_configvar(group,2160 "archive_orphans",2161 Checkbox(title = _("Force message archiving"),2162 label = _("Archive messages that do not match any rule"),2163 help = _("When this option is enabled then messages that do not match "2164 "a rule will be archived into the event history anyway (Messages "2165 "that do match a rule will be archived always, as long as they are not "2166 "explicitely dropped are being aggregated by counting.)"),2167 default_value = False),2168 domain = "mkeventd",2169 )2170 register_configvar(group,2171 "hostname_translation",2172 HostnameTranslation(2173 title = _("Hostname translation for incoming messages"),2174 help = _("When the Event Console receives a message than the host name "2175 "that is contained in that message will be translated using "2176 "this configuration. This can be used for unifying host names "2177 "from message with those of actively monitored hosts. Note: this translation "2178 "is happening before any rule is being applied.")2179 ),2180 domain = "mkeventd",2181 )2182 register_configvar(group,2183 "history_rotation",2184 DropdownChoice(2185 title = _("Event history logfile rotation"),2186 help = _("Specify at which time period a new file for the event history will be created."),2187 choices = [2188 ( "daily", _("daily")),2189 ( "weekly", _("weekly"))2190 ],2191 default_value = "daily",2192 ),2193 domain = "mkeventd",2194 )2195 register_configvar(group,2196 "history_lifetime",2197 Integer(2198 title = _("Event history lifetime"),2199 help = _("After this number of days old logfile of event history "2200 "will be deleted."),2201 default_value = 365,2202 unit = _("days"),2203 minvalue = 1,2204 ),2205 domain = "mkeventd",2206 )2207 register_configvar(group,2208 "socket_queue_len",2209 Integer(2210 title = _("Max. number of pending connections to the status socket"),2211 help = _("When the Multisite GUI or the active check check_mkevents connects "2212 "to the socket of the event daemon in order to retrieve information "2213 "about current and historic events then its connection request might "2214 "be queued before being processed. This setting defines the number of unaccepted "2215 "connections to be queued before refusing new connections."),2216 minvalue = 1,2217 default_value = 10,2218 label = "max.",2219 unit = _("pending connections"),2220 ),2221 domain = "mkeventd",2222 )2223 register_configvar(group,2224 "eventsocket_queue_len",2225 Integer(2226 title = _("Max. number of pending connections to the event socket"),2227 help = _("The event socket is an alternative way for sending events "2228 "to the Event Console. It is used by the Check_MK logwatch check "2229 "when forwarding log messages to the Event Console. "2230 "This setting defines the number of unaccepted "2231 "connections to be queued before refusing new connections."),2232 minvalue = 1,2233 default_value = 10,2234 label = "max.",2235 unit = _("pending connections"),2236 ),2237 domain = "mkeventd",2238 )2239 register_configvar(group,2240 "translate_snmptraps",2241 Transform(2242 CascadingDropdown(2243 choices = [2244 (False, _("Do not translate SNMP traps")),2245 (True, _("Translate SNMP traps using the available MIBs"),2246 Dictionary(2247 elements = [2248 ("add_description", FixedValue(True,2249 title = _("Add OID descriptions"),2250 totext = _("Append descriptions of OIDs to message texts"),2251 )),2252 ],2253 ),2254 ),2255 ],2256 ),2257 title = _("Translate SNMP traps"),2258 label = _("Use the available SNMP MIBs to translate contents of the SNMP traps"),2259 help = _("When this option is enabled all available SNMP MIB files will be used "2260 "to translate the incoming SNMP traps. Information which can not be "2261 "translated, e.g. because a MIB is missing, are written untouched to "2262 "the event message."),2263 forth = lambda v: v == True and (v, {}) or v,2264 ),2265 domain = "mkeventd",2266 )2267 # A few settings for Multisite and WATO2268 register_configvar(_("User Interface"),2269 "mkeventd_connect_timeout",2270 Integer(2271 title = _("Connect timeout to status socket of Event Console"),2272 help = _("When the Multisite GUI connects the socket of the event daemon "2273 "in order to retrieve information about current and historic events "2274 "then this timeout will be applied."),2275 minvalue = 1,2276 maxvalue = 120,2277 default_value = 10,2278 unit = "sec",2279 ),2280 domain = "multisite",2281 )2282 register_configvar(_("Administration Tool (WATO)"),2283 "mkeventd_pprint_rules",2284 Checkbox(title = _("Pretty-Print rules in config file of Event Console"),2285 label = _("enable pretty-printing of rules"),2286 help = _("When the WATO module of the Event Console saves rules to the file "2287 "<tt>mkeventd.d/wato/rules.mk</tt> it usually prints the Python "2288 "representation of the rules-list into one single line by using the "2289 "native Python code generator. Enabling this option switches to <tt>pprint</tt>, "2290 "which nicely indents everything. While this is a bit slower for large "2291 "rulesets it makes debugging and manual editing simpler."),2292 default_value = False),2293 domain = "multisite",2294 )2295 register_configvar(_("User Interface"),2296 "mkeventd_contact_group_handling",2297 DropdownChoice(2298 title = _("Precedence of contact groups of events"),2299 choices = [2300 ( "host", _("Host's contact groups have precedence") ),2301 ( "rule", _("Contact groups in rule have precedence") ),2302 ],2303 help = _("Here you can specify which contact groups shall have "2304 "precedence when both the host of an event can be found in the "2305 "monitoring and the event rule has defined contact groups for the event."),2306 ),2307 domain = "multisite",2308 )2309# Settings that should also be avaiable on distributed Sites that2310# do not run an own eventd but want to query one or send notifications2311# to one.2312group = _("Notifications")2313register_configvar(group,2314 "mkeventd_notify_contactgroup",2315 GroupSelection(2316 "contact",2317 title = _("Send notifications to Event Console"),2318 no_selection = _("(don't send notifications to Event Console)"),2319 label = _("send notifications of contactgroup:"),2320 help = _("If you select a contact group here, then all notifications of "2321 "hosts and services in that contact group will be sent to the "2322 "event console. <b>Note</b>: you still need to create a rule "2323 "matching those messages in order to have events created. <b>Note (2)</b>: "2324 "If you are using the Check_MK Micro Core then this setting is deprecated. "2325 "Please use the notification plugin <i>Forward Notification to Event Console</i> instead."),2326 default_value = '',2327 ),2328 domain = "multisite",2329 need_restart = True)2330register_configvar(group,2331 "mkeventd_notify_remotehost",2332 Optional(2333 TextAscii(2334 title = _("Host running Event Console"),2335 attrencode = True,2336 ),2337 title = _("Send notifications to remote Event Console"),2338 help = _("This will send the notification to a Check_MK Event Console on a remote host "2339 "by using syslog. <b>Note</b>: this setting will only be applied if no Event "2340 "Console is running locally in this site! That way you can use the same global "2341 "settings on your central and decentralized system and makes distributed WATO "2342 "easier. Please also make sure that <b>Send notifications to Event Console</b> "2343 "is enabled."),2344 label = _("Send to remote Event Console via syslog"),2345 none_label = _("Do not send to remote host"),2346 ),2347 domain = "multisite",2348 need_restart = True)2349register_configvar(group,2350 "mkeventd_notify_facility",2351 DropdownChoice(2352 title = _("Syslog facility for Event Console notifications"),2353 help = _("When sending notifications from the monitoring system to the event console "2354 "the following syslog facility will be set for these messages. Choosing "2355 "a unique facility makes creation of rules easier."),2356 choices = mkeventd.syslog_facilities,2357 default_value = 16, # local02358 ),2359 domain = "multisite",2360 need_restart = True)2361register_rulegroup("eventconsole",2362 _("Event Console"),2363 _("Settings and Checks dealing with the Check_MK Event Console"))2364group = "eventconsole"2365def convert_mkevents_hostspec(value):2366 if type(value) == list:2367 return value2368 elif value == "$HOSTADDRESS$":2369 return [ "$HOSTADDRESS$" ]2370 elif value == "$HOSTNAME$":2371 return [ "$HOSTNAME$" ]2372 elif value == "$HOSTNAME$/$HOSTADDRESS$":2373 return [ "$HOSTNAME$", "$HOSTADDRESS$" ]2374 else: # custom2375 return value2376register_rule(2377 group,2378 "active_checks:mkevents",2379 Dictionary(2380 title = _("Check event state in Event Console"),2381 help = _("This check is part of the Check_MK Event Console and will check "2382 "if there are any open events for a certain host (and maybe a certain "2383 "application on that host. The state of the check will reflect the status "2384 "of the worst open event for that host."),2385 elements = [2386 ( "hostspec",2387 Transform(2388 Alternative(2389 title = _("Host specification"),2390 elements = [2391 ListChoice(2392 title = _("Match the hosts with..."),2393 choices = [2394 ( '$HOSTNAME$', _("Hostname") ),2395 ( '$HOSTADDRESS$', _("IP address" ) ),2396 ( '$HOSTALIAS$', _("Alias" ) ),2397 ]2398 ),2399 TextAscii(allow_empty = False, attrencode = True, title = "Specify host explicitely"),2400 ],2401 default_value = [ '$HOSTNAME$', '$HOSTADDRESS$' ]2402 ),2403 help = _("When quering the event status you can either use the monitoring "2404 "host name, the IP address, the host alias or a custom host name for referring to a "2405 "host. This is needed in cases where the event source (syslog, snmptrapd) "2406 "do not send a host name that matches the monitoring host name."),2407 forth = convert_mkevents_hostspec2408 )2409 ),2410 ( "item",2411 TextAscii(2412 title = _("Item (Used in service description)"),2413 help = _("If you enter an item name here, this will be used as "2414 "part of the service description after the prefix \"Events \". "2415 "The prefix plus the configured item must result in an unique "2416 "service description per host. If you leave this empty either the "2417 "string provided in \"Application\" is used as item or the service "2418 "gets no item when the \"Application\" field is also not configured."),2419 allow_empty = False,2420 )2421 ),2422 ( "application",2423 RegExp(2424 title = _("Application (regular expression)"),2425 help = _("If you enter an application name here then only "2426 "events for that application name are counted. You enter "2427 "a regular expression here that must match a <b>part</b> "2428 "of the application name. Use anchors <tt>^</tt> and <tt>$</tt> "2429 "if you need a complete match."),2430 allow_empty = False,2431 )2432 ),2433 ( "ignore_acknowledged",2434 FixedValue(2435 True,2436 title = _("Ignore Acknowledged Events"),2437 help = _("If you check this box then only open events are honored when "2438 "determining the event state. Acknowledged events are displayed "2439 "(i.e. their count) but not taken into account."),2440 totext = _("acknowledged events will not be honored"),2441 )2442 ),2443 ( "less_verbose",2444 FixedValue(2445 True,2446 title = _("Less Verbose Output"),2447 help = _("If enabled the check reports less information in its output. "2448 "You will see no information regarding the worst state or unacknowledged events. "2449 " For example a default output without this option is "2450 "<tt>WARN - 1 events (1 unacknowledged), worst state is WARN (Last line: Incomplete Content)</tt>."2451 "Output with less verbosity: "2452 "<tt>WARN - 1 events (Worst line: Incomplete Content)</tt><br>"2453 ),2454 )2455 ),2456 ( "remote",2457 Alternative(2458 title = _("Access to the Event Console"),2459 style = "dropdown",2460 elements = [2461 FixedValue(2462 None,2463 title = _("Connect to the local Event Console"),2464 totext = _("local connect"),2465 ),2466 Tuple(2467 elements = [2468 TextAscii(2469 title = _("Hostname/IP address of Event Console:"),2470 allow_empty = False,2471 attrencode = True,2472 ),2473 Integer(2474 title = _("TCP Port number:"),2475 minvalue = 1,2476 maxvalue = 65535,2477 default_value = 6558,2478 ),2479 ],2480 title = _("Access via TCP"),2481 help = _("In a distributed setup where the Event Console is not running in the same "2482 "site as the host is monitored you need to access the remote Event Console "2483 "via TCP. Please make sure that this is activated in the global settings of "2484 "the event console. The default port number is 6558."),2485 ),2486 TextAscii(2487 title = _("Access via UNIX socket"),2488 allow_empty = False,2489 size = 64,2490 attrencode = True,2491 ),2492 ],2493 default_value = defaults.omd_root2494 and defaults.omd_root + "/tmp/run/mkeventd/status"2495 or defaults.livestatus_unix_socket.split("/",1)[0] + "/mkeventd/status"2496 )2497 ),2498 ],2499 optional_keys = [ "application", "remote", "ignore_acknowledged", "less_verbose", "item" ],2500 ),2501 match = 'all',2502)2503sl_help = _("A service level is a number that describes the business impact of a host or "2504 "service. This level can be used in rules for notifications, as a filter in "2505 "views or as a criteria in rules for the Event Console. A higher service level "2506 "is assumed to be more business critical. This ruleset allows to assign service "2507 "levels to hosts and/or services. Note: if you assign a service level to "2508 "a host with the ruleset <i>Service Level of hosts</i>, then this level is "2509 "inherited to all services that do <b>not</b> have explicitely assigned a service "2510 "with the ruleset <i>Service Level of services</i>. Assigning no service level "2511 "is equal to defining a level of 0.<br><br>The list of available service "2512 "levels is configured via a <a href='%s'>global option.</a>" %2513 "wato.py?varname=mkeventd_service_levels&mode=edit_configvar")2514register_rule(2515 "grouping",2516 "extra_host_conf:_ec_sl",2517 DropdownChoice(2518 title = _("Service Level of hosts"),2519 help = sl_help,2520 choices = mkeventd.service_levels,2521 ),2522 match = 'first',2523)2524register_rule(2525 "grouping",2526 "extra_service_conf:_ec_sl",2527 DropdownChoice(2528 title = _("Service Level of services"),2529 help = sl_help + _(" Note: if no service level is configured for a service "2530 "then that of the host will be used instead (if configured)."),2531 choices = mkeventd.service_levels,2532 ),2533 itemtype = 'service',2534 match = 'first',2535)2536contact_help = _("This rule set is useful if you send your monitoring notifications "2537 "into the Event Console. The contact information that is set by this rule "2538 "will be put into the resulting event in the Event Console.")2539contact_regex = r"^[^;'$|]*$"2540contact_regex_error = _("The contact information must not contain one of the characters <tt>;</tt> <tt>'</tt> <tt>|</tt> or <tt>$</tt>")2541register_rule(2542 group,2543 "extra_host_conf:_ec_contact",2544 TextUnicode(2545 title = _("Host contact information"),2546 help = contact_help,2547 size = 80,2548 regex = contact_regex,2549 regex_error = contact_regex_error,2550 attrencode = True,2551 ),2552 match = 'first',2553)2554register_rule(2555 group,2556 "extra_service_conf:_ec_contact",2557 TextUnicode(2558 title = _("Service contact information"),2559 help = contact_help + _(" Note: if no contact information is configured for a service "2560 "then that of the host will be used instead (if configured)."),2561 size = 80,2562 regex = contact_regex,2563 regex_error = contact_regex_error,2564 attrencode = True,2565 ),2566 itemtype = 'service',2567 match = 'first',2568)2569#.2570# .--Notifications-------------------------------------------------------.2571# | _ _ _ _ __ _ _ _ |2572# | | \ | | ___ | |_(_)/ _(_) ___ __ _| |_(_) ___ _ __ ___ |2573# | | \| |/ _ \| __| | |_| |/ __/ _` | __| |/ _ \| '_ \/ __| |2574# | | |\ | (_) | |_| | _| | (_| (_| | |_| | (_) | | | \__ \ |2575# | |_| \_|\___/ \__|_|_| |_|\___\__,_|\__|_|\___/|_| |_|___/ |2576# | |2577# +----------------------------------------------------------------------+2578# | Stuff for sending monitoring notifications into the event console. |2579# '----------------------------------------------------------------------'2580def mkeventd_update_notifiation_configuration(hosts):2581 # Setup notification into the Event Console. Note: If2582 # the event console is not activated then also the global2583 # default settings are missing and we must skip this code.2584 # This can happen in a D-WATO setup where the master has2585 # enabled the EC and the slave not.2586 try:2587 contactgroup = config.mkeventd_notify_contactgroup2588 remote_console = config.mkeventd_notify_remotehost2589 except:2590 return2591 if not remote_console:2592 remote_console = ""2593 path = defaults.nagios_conf_dir + "/mkeventd_notifications.cfg"2594 if not contactgroup and os.path.exists(path):2595 os.remove(path)2596 elif contactgroup:2597 file(path, "w").write("""# Created by Check_MK Event Console2598# This configuration will send notifications about hosts and2599# services in the contact group '%(group)s' to the Event Console.2600define contact {2601 contact_name mkeventd2602 alias "Notifications for Check_MK Event Console"2603 contactgroups %(group)s2604 host_notification_commands mkeventd-notify-host2605 service_notification_commands mkeventd-notify-service2606 host_notification_options d,u,r2607 service_notification_options c,w,u,r2608 host_notification_period 24X72609 service_notification_period 24X72610 email none2611}2612define command {2613 command_name mkeventd-notify-host2614 command_line mkevent -n %(facility)s '%(remote)s' $HOSTSTATEID$ '$HOSTNAME$' '' '$HOSTOUTPUT$' '$_HOSTEC_SL$' '$_HOSTEC_CONTACT$'2615}2616define command {2617 command_name mkeventd-notify-service2618 command_line mkevent -n %(facility)s '%(remote)s' $SERVICESTATEID$ '$HOSTNAME$' '$SERVICEDESC$' '$SERVICEOUTPUT$' '$_SERVICEEC_SL$' '$_SERVICEEC_CONTACT$' '$_HOSTEC_SL$' '$_HOSTEC_CONTACT$'2619}2620""" % { "group" : contactgroup, "facility" : config.mkeventd_notify_facility, "remote" : remote_console })2621register_hook("pre-activate-changes", mkeventd_update_notifiation_configuration)2622# Only register the reload hook when mkeventd is enabled2623if mkeventd_enabled:...
bibfield_config_engine.py
Source:bibfield_config_engine.py
...277 if source_format not in rules:278 #Allow several tags point to the same json id279 rules[source_format] = []280 (depends_on, only_if, only_if_master_value, parse_first) = self._create_decorators_content(creator)281 self._create_legacy_rules(creator.legacy, json_id, source_format)282 rules[source_format].append({'source_tag' : creator.source_tag[0].split(),283 'value' : creator.value[0],284 'depends_on' : depends_on,285 'only_if' : only_if,286 'only_if_master_value' : only_if_master_value,287 'parse_first' : parse_first})288 #Chech duplicate names to overwrite configuration289 if not json_id in self.config_rules:290 self.config_rules[json_id] = {'inherit_from' : inherit_from,291 'rules' : rules,292 'checker' : [],293 'documentation' : BibFieldDict(),294 'producer' : {},295 'type' : 'real',296 'aliases' : aliases,297 'persistent_identifier': persistent_id,298 'overwrite' : False}299 else:300 self.config_rules[json_id]['overwrite'] = True301 self.config_rules[json_id]['rules'].update(rules)302 self.config_rules[json_id]['aliases'] = \303 aliases or self.config_rules[json_id]['aliases']304 self.config_rules[json_id]['persistent_identifier'] = \305 persistent_id or self.config_rules[json_id]['persistent_identifier']306 self.config_rules[json_id]['inherit_from'] = \307 inherit_from or self.config_rules[json_id]['inherit_from']308 self._create_checkers(rule)309 self._create_documentation(rule)310 self._create_producer(rule)311 def _create_derived_calculated_rule(self, rule):312 """313 Creates the config_rules entries for the virtual fields314 The result is similar to the one of real fields but in this case there is315 only one rule.316 """317 json_id = rule.json_id[0]318 #Chech duplicate names319 if json_id in self.config_rules:320 raise BibFieldParserException("Name error: '%s' field name already defined"321 % (rule.json_id[0],))322 aliases = []323 if rule.aliases:324 aliases = rule.aliases.asList()325 if re.search('^_[a-zA-Z0-9]', json_id):326 aliases.append(json_id[1:])327 do_not_cache = False328 if rule.do_not_cache:329 do_not_cache = True330 persistent_id = None331 if rule.persistent_identifier:332 persistent_id = int(rule.persistent_identifier[0][0])333 (depends_on, only_if, only_if_master_value, parse_first) = self._create_decorators_content(rule)334 self._create_legacy_rules(rule.legacy, json_id)335 self.config_rules[json_id] = {'rules' : {},336 'checker' : [],337 'documentation': BibFieldDict(),338 'producer' : {},339 'aliases' : aliases,340 'type' : rule.type_field[0],341 'persistent_identifier' : persistent_id,342 'overwrite' : False}343 self.config_rules[json_id]['rules'] = {'value' : rule.value[0],344 'depends_on' : depends_on,345 'only_if' : only_if,346 'only_if_master_value': only_if_master_value,347 'parse_first' : parse_first,348 'do_not_cache' : do_not_cache}349 self._create_checkers(rule)350 self._create_documentation(rule)351 self._create_producer(rule)352 def _create_decorators_content(self, rule):353 """354 Extracts from the rule all the possible decorators.355 """356 depends_on = only_if = only_if_master_value = parse_first = None357 if rule.depends_on:358 depends_on = rule.depends_on[0]359 if rule.only_if:360 only_if = rule.only_if[0]361 if rule.only_if_master_value:362 only_if_master_value = rule.only_if_master_value[0]363 if rule.parse_first:364 parse_first = rule.parse_first[0]365 return (depends_on, only_if, only_if_master_value, parse_first)366 def _create_legacy_rules(self, legacy_rules, json_id, source_format=None):367 """368 Creates the legacy rules dictionary:369 {'100' : ['authors[0]'],370 '100__' : ['authors[0]'],371 '100__%': ['authors[0]'],372 '100__a': ['auhtors[0].full_name'],373 .......374 }375 """376 if not legacy_rules:377 return378 for legacy_rule in legacy_rules:379 legacy_rule = eval(legacy_rule[0])380 if source_format is None:...
bibfield.py
Source:bibfield.py
1# -*- coding: utf-8 -*-2##3## This file is part of Invenio.4## Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2013 CERN.5##6## Invenio is free software; you can redistribute it and/or7## modify it under the terms of the GNU General Public License as8## published by the Free Software Foundation; either version 2 of the9## License, or (at your option) any later version.10##11## Invenio is distributed in the hope that it will be useful, but12## WITHOUT ANY WARRANTY; without even the implied warranty of13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14## General Public License for more details.15##16## You should have received a copy of the GNU General Public License17## along with Invenio; if not, write to the Free Software Foundation, Inc.,18## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.19"""20BibField engine21"""22__revision__ = "$Id$"23import os24try:25 import cPickle as pickle26except:27 import pickle28from pprint import pformat29from werkzeug import import_string30from invenio.config import CFG_PYLIBDIR, CFG_LOGDIR31from invenio.datastructures import LaziestDict32from invenio.dbquery import run_sql33from invenio.errorlib import register_exception34from invenio.signalutils import record_after_update35from invenio.bibfield_jsonreader import JsonReader36from invenio.bibfield_utils import BlobWrapper, BibFieldDict37# Lazy loader of bibfield readers38def reader_discover(key):39 try:40 candidate = import_string('invenio.bibfield_%sreader:readers' % (key, ))41 if issubclass(candidate, JsonReader):42 return candidate43 except:44 register_exception()45 raise KeyError(key)46CFG_BIBFIELD_READERS = LaziestDict(reader_discover)47@record_after_update.connect48def delete_record_cache(sender, recid=None, **kwargs):49 get_record(recid, reset_cache=True)50def create_record(blob, master_format='marc', verbose=0, **additional_info):51 """52 Creates a record object from the blob description using the apropiate reader53 for it.54 @return Record object55 """56 blob_wrapper = BlobWrapper(blob=blob, master_format=master_format, **additional_info)57 return CFG_BIBFIELD_READERS[master_format](blob_wrapper, check=True)58def create_records(blob, master_format='marc', verbose=0, **additional_info):59 """60 Creates a list of records from the blod descriptions using the split_records61 function to divide then.62 @see create_record()63 @return List of record objects initiated by the functions create_record()64 """65 record_blods = CFG_BIBFIELD_READERS[master_format].split_blob(blob, additional_info.get('schema', None))66 return [create_record(record_blob, master_format, verbose=verbose, **additional_info) for record_blob in record_blods]67def get_record(recid, reset_cache=False, fields=()):68 """69 Record factory, it retrieves the record from bibfmt table if it is there,70 if not, or reset_cache is set to True, it searches for the appropriate71 reader to create the representation of the record.72 @return: Bibfield object representing the record or None if the recid is not73 present in the system74 """75 record = None76 #Search for recjson77 if not reset_cache:78 res = run_sql("SELECT value FROM bibfmt WHERE id_bibrec=%s AND format='recjson'",79 (recid,))80 if res:81 record = JsonReader(BlobWrapper(pickle.loads(res[0][0])))82 #There is no version cached or we want to renew it83 #Then retrieve information and blob84 if not record or reset_cache:85 blob_wrapper = _build_wrapper(recid)86 if not blob_wrapper:87 return None88 record = CFG_BIBFIELD_READERS[blob_wrapper.master_format](blob_wrapper)89 #Update bibfmt for future uses90 run_sql("REPLACE INTO bibfmt(id_bibrec, format, last_updated, value) VALUES (%s, 'recjson', NOW(), %s)",91 (recid, pickle.dumps((record.rec_json))))92 if fields:93 chunk = BibFieldDict()94 for key in fields:95 chunk[key] = record.get(key)96 record = chunk97 return record98def guess_legacy_field_names(fields, master_format='marc'):99 """100 Using the legacy rules written in the config file (@legacy) tries to find101 the equivalent json field for one or more legacy fields.102 >>> guess_legacy_fields(('100__a', '245'), 'marc')103 {'100__a':['authors[0].full_name'], '245':['title']}104 """105 from invenio.bibfield_config import legacy_rules106 res = {}107 if isinstance(fields, basestring):108 fields = (fields, )109 for field in fields:110 try:111 res[field] = legacy_rules[master_format].get(field, [])112 except:113 res[field] = []114 return res115def _build_wrapper(recid):116 #TODO: update to look inside mongoDB for the parameters and the blob117 # Now is just working for marc and recstruct118 try:119 master_format = run_sql("SELECT master_format FROM bibrec WHERE id=%s", (recid,))[0][0]120 except:121 return None122 schema = 'recstruct'123 if master_format == 'marc':124 from invenio.search_engine import get_record as se_get_record125 blob = se_get_record(recid)126 else:127 return None...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!