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!!
