Fix typecheck idiom in cmk/gui/{plugins,wato}
[check_mk.git] / cmk / gui / wato / __init__.py
bloba84dc9843cc16d5adfd1756e223cbd9842f374fe
1 #!/usr/bin/env python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # WATO
29 # This file contain acutal page handlers and WATO modes. It does HTML creation
30 # and implement AJAX handlers. It uses classes, functions and globals
31 # from watolib.py.
33 # .--README--------------------------------------------------------------.
34 # | ____ _ |
35 # | | _ \ ___ __ _ __| | _ __ ___ ___ |
36 # | | |_) / _ \/ _` |/ _` | | '_ ` _ \ / _ \ |
37 # | | _ < __/ (_| | (_| | | | | | | | __/ |
38 # | |_| \_\___|\__,_|\__,_| |_| |_| |_|\___| |
39 # | |
40 # +----------------------------------------------------------------------+
41 # | A few words about the implementation details of WATO. |
42 # `----------------------------------------------------------------------'
44 # [1] Files and Folders
45 # WATO organizes hosts in folders. A wato folder is represented by a
46 # OS directory. If the folder contains host definitions, then in that
47 # directory a file name "hosts.mk" is kept.
48 # The directory hierarchy of WATO is rooted at etc/check_mk/conf.d/wato.
49 # All files in and below that directory are kept by WATO. WATO does not
50 # touch any other files or directories in conf.d.
51 # A *path* in WATO means a relative folder path to that directory. The
52 # root folder has the empty path (""). Folders are separated by slashes.
53 # Each directory contains a file ".wato" which keeps information needed
54 # by WATO but not by Check_MK itself.
56 # [3] Convention for variable names:
57 # site_id --> The id of a site, None for the local site in non-distributed setup
58 # site --> The dictionary datastructure of a site
59 # host_name --> A string containing a host name
60 # host --> An instance of the class Host
61 # folder_path --> A relative specification of a folder (e.g. "linux/prod")
62 # folder --> An instance of the class Folder
65 # .--Init----------------------------------------------------------------.
66 # | ___ _ _ |
67 # | |_ _|_ __ (_) |_ |
68 # | | || '_ \| | __| |
69 # | | || | | | | |_ |
70 # | |___|_| |_|_|\__| |
71 # | |
72 # +----------------------------------------------------------------------+
73 # | Importing, Permissions, global variables |
74 # `----------------------------------------------------------------------'
76 import abc
77 import ast
78 import csv
79 import datetime
80 import fcntl
81 import glob
82 import json
83 import math
84 import multiprocessing
85 import pprint
86 import Queue
87 import random
88 import re
89 import tarfile
90 import shutil
91 import socket
92 import subprocess
93 import sys
94 import time
95 import traceback
96 import copy
97 from hashlib import sha256
99 import cmk
100 import cmk.paths
101 import cmk.translations
102 import cmk.store as store
103 from cmk.regex import regex
104 from cmk.defines import short_service_state_name
105 import cmk.render as render
107 import cmk.gui.utils as utils
108 import cmk.gui.sites as sites
109 import cmk.gui.config as config
110 import cmk.gui.table as table
111 import cmk.gui.multitar as multitar
112 import cmk.gui.userdb as userdb
113 import cmk.gui.weblib as weblib
114 import cmk.gui.mkeventd
115 import cmk.gui.forms as forms
116 import cmk.gui.backup as backup
117 import cmk.gui.watolib as watolib
118 import cmk.gui.background_job as background_job
119 import cmk.gui.gui_background_job as gui_background_job
120 import cmk.gui.i18n
121 import cmk.gui.pages
122 import cmk.gui.view_utils
123 import cmk.gui.plugins.wato.utils
124 import cmk.gui.plugins.wato.utils.base_modes
125 import cmk.gui.wato.mkeventd
126 from cmk.gui.i18n import _u, _
127 from cmk.gui.globals import html
128 from cmk.gui.htmllib import HTML
129 from cmk.gui.exceptions import MKGeneralException, MKUserError, MKAuthException, \
130 MKInternalError, MKException
131 from cmk.gui.log import logger
132 from cmk.gui.display_options import display_options
133 from cmk.gui.plugins.wato.utils.base_modes import WatoMode, WatoWebApiMode
135 from cmk.gui.wato.pages.activate_changes import (
136 ModeActivateChanges,
137 ModeAjaxStartActivation,
138 ModeAjaxActivationState
140 from cmk.gui.wato.pages.analyze_configuration import ModeAnalyzeConfig
141 from cmk.gui.wato.pages.audit_log import ModeAuditLog
142 from cmk.gui.wato.pages.automation import ModeAutomationLogin, ModeAutomation
143 from cmk.gui.wato.pages.backup import (
144 ModeBackup,
145 ModeBackupTargets,
146 ModeEditBackupTarget,
147 ModeEditBackupJob,
148 ModeBackupJobState,
149 ModeBackupKeyManagement,
150 ModeBackupEditKey,
151 ModeBackupUploadKey,
152 ModeBackupDownloadKey,
153 ModeBackupRestore,
155 from cmk.gui.wato.pages.bulk_discovery import ModeBulkDiscovery
156 from cmk.gui.wato.pages.bulk_edit import ModeBulkEdit, ModeBulkCleanup
157 from cmk.gui.wato.pages.bulk_import import ModeBulkImport
158 from cmk.gui.wato.pages.check_catalog import ModeCheckManPage, ModeCheckPlugins
159 from cmk.gui.wato.pages.custom_attributes import (
160 ModeEditCustomAttr,
161 ModeEditCustomUserAttr,
162 ModeEditCustomHostAttr,
163 ModeCustomAttrs,
164 ModeCustomUserAttrs,
165 ModeCustomHostAttrs,
167 from cmk.gui.wato.pages.download_agents import ModeDownloadAgents
168 from cmk.gui.wato.pages.folders import (
169 ModeFolder,
170 ModeAjaxPopupMoveToFolder,
171 ModeEditFolder,
172 ModeCreateFolder,
173 ModeAjaxSetFoldertree,
175 from cmk.gui.wato.pages.global_settings import (
176 GlobalSettingsMode,
177 EditGlobalSettingMode,
178 ModeEditGlobals,
179 ModeEditGlobalSetting,
180 ModeEditSiteGlobalSetting
182 from cmk.gui.wato.pages.groups import (
183 ModeGroups,
184 ModeHostgroups,
185 ModeServicegroups,
186 ModeContactgroups,
187 ModeEditGroup,
188 ModeEditHostgroup,
189 ModeEditServicegroup,
190 ModeEditContactgroup,
192 from cmk.gui.wato.pages.host_diagnose import ModeDiagHost
193 from cmk.gui.wato.pages.host_rename import ModeBulkRenameHost, ModeRenameHost
194 from cmk.gui.wato.pages.host_tags import (
195 ModeHostTags,
196 ModeEditHosttagConfiguration,
197 ModeEditAuxtag,
198 ModeEditHosttagGroup,
200 from cmk.gui.wato.pages.hosts import ModeEditHost, ModeCreateHost, ModeCreateCluster
201 from cmk.gui.wato.pages.icons import ModeIcons
202 from cmk.gui.wato.pages.ldap import ModeLDAPConfig, ModeEditLDAPConnection
203 from cmk.gui.wato.pages.main import ModeMain
204 from cmk.gui.wato.pages.not_implemented import ModeNotImplemented
205 from cmk.gui.wato.pages.notifications import (
206 ModeNotifications,
207 ModeUserNotifications,
208 ModePersonalUserNotifications,
209 ModeEditNotificationRule,
210 ModeEditPersonalNotificationRule,
212 from cmk.gui.wato.pages.object_parameters import ModeObjectParameters
213 from cmk.gui.wato.pages.parentscan import ModeParentScan
214 from cmk.gui.wato.pages.password_store import ModePasswords, ModeEditPassword
215 from cmk.gui.wato.pages.pattern_editor import ModePatternEditor
216 from cmk.gui.wato.pages.random_hosts import ModeRandomHosts
217 from cmk.gui.wato.pages.read_only import ModeManageReadOnly
218 from cmk.gui.wato.pages.roles import (
219 ModeRoles,
220 ModeEditRole,
221 ModeRoleMatrix,
223 from cmk.gui.wato.pages.rulesets import (
224 ModeRuleEditor,
225 ModeRulesets,
226 ModeStaticChecksRulesets,
227 ModeEditRuleset,
228 ModeRuleSearch,
229 ModeEditRule,
230 ModeCloneRule,
231 ModeNewRule,
233 from cmk.gui.wato.pages.search import ModeSearch
234 from cmk.gui.wato.pages.services import (
235 ModeDiscovery,
236 ModeFirstDiscovery,
237 ModeAjaxExecuteCheck
239 from cmk.gui.wato.pages.sites import (
240 ModeSites,
241 ModeEditSite,
242 ModeDistributedMonitoring,
243 ModeEditSiteGlobals
245 from cmk.gui.wato.pages.timeperiods import (
246 ModeTimeperiods,
247 ModeTimeperiodImportICal,
248 ModeEditTimeperiod
250 from cmk.gui.wato.pages.users import ModeUsers, ModeEditUser
252 import cmk.gui.plugins.wato
253 import cmk.gui.plugins.wato.bi
255 if not cmk.is_raw_edition():
256 import cmk.gui.cee.plugins.wato
258 if cmk.is_managed_edition():
259 import cmk.gui.cme.managed as managed
260 import cmk.gui.cme.plugins.wato
261 import cmk.gui.cme.plugins.wato.managed
262 else:
263 managed = None
266 wato_root_dir = watolib.wato_root_dir
267 multisite_dir = watolib.multisite_dir
269 # TODO: Kept for old plugin compatibility. Remove this one day
270 from cmk.gui.valuespec import * # pylint: disable=wildcard-import
271 syslog_facilities = cmk.gui.mkeventd.syslog_facilities
272 ALL_HOSTS = watolib.ALL_HOSTS
273 ALL_SERVICES = watolib.ALL_SERVICES
274 NEGATE = watolib.NEGATE
275 NO_ITEM = watolib.NO_ITEM
276 ENTRY_NEGATE_CHAR = watolib.ENTRY_NEGATE_CHAR
277 from cmk.gui.plugins.wato import (
278 may_edit_ruleset,
279 monitoring_macro_help,
280 UserIconOrAction,
281 SNMPCredentials,
282 HostnameTranslation,
283 GroupSelection,
284 rule_option_elements,
285 register_check_parameters,
286 sort_sites,
287 Levels,
288 PredictiveLevels,
289 EventsMode,
290 mode_registry,
293 # Make some functions of watolib available to WATO plugins without using the
294 # watolib module name. This is mainly done for compatibility reasons to keep
295 # the current plugin API functions working
296 from cmk.gui.watolib import (
297 PasswordStore,
298 TimeperiodSelection,
299 register_rulegroup,
300 register_rule,
301 register_configvar,
302 register_configvar_group,
303 register_hook,
304 add_replication_paths,
305 UserSelection,
306 ConfigDomainGUI,
307 ConfigDomainCore,
308 ConfigDomainOMD,
309 ConfigDomainEventConsole,
310 configvar_order,
311 add_change,
312 add_service_change,
313 site_neutral_path,
314 register_notification_parameters,
315 declare_host_attribute,
316 Attribute,
317 ContactGroupsAttribute,
318 NagiosTextAttribute,
319 ValueSpecAttribute,
320 ACTestCategories,
321 ACTest,
322 ACResultCRIT,
323 ACResultWARN,
324 ACResultOK,
325 LivestatusViaTCP,
326 SiteBackupJobs,
327 make_action_link,
328 is_a_checkbox,
329 get_search_expression,
330 may_edit_configvar,
331 multifolder_host_rule_match_conditions,
332 simple_host_rule_match_conditions,
333 transform_simple_to_multi_host_rule_match_conditions,
334 WatoBackgroundJob,
335 init_wato_datastructures,
336 get_hostnames_from_checkboxes,
337 get_hosts_from_checkboxes,
341 modes = {}
343 from cmk.gui.plugins.wato.utils.html_elements import (
344 wato_styles,
345 wato_confirm,
346 wato_html_head,
347 initialize_wato_html_head,
348 wato_html_footer,
349 search_form,
352 from cmk.gui.plugins.wato.utils.context_buttons import (
353 global_buttons,
354 changelog_button,
355 home_button,
356 host_status_button,
357 service_status_button,
358 folder_status_button,
361 from cmk.gui.plugins.wato.utils.main_menu import (
362 MainMenu,
363 MenuItem,
364 WatoModule,
365 register_modules,
366 get_modules,
371 # .--Main----------------------------------------------------------------.
372 # | __ __ _ |
373 # | | \/ | __ _(_)_ __ |
374 # | | |\/| |/ _` | | '_ \ |
375 # | | | | | (_| | | | | | |
376 # | |_| |_|\__,_|_|_| |_| |
377 # | |
378 # +----------------------------------------------------------------------+
379 # | Der Seitenaufbau besteht aus folgenden Teilen: |
380 # | 1. Kontextbuttons: wo kann man von hier aus hinspringen, ohne Aktion |
381 # | 2. Verarbeiten einer Aktion, falls eine gültige Transaktion da ist |
382 # | 3. Anzeigen von Inhalten |
383 # | |
384 # | Der Trick: welche Inhalte angezeigt werden, hängt vom Ausgang der |
385 # | Aktion ab. Wenn man z.B. bei einem Host bei "Create new host" auf |
386 # | [Save] klickt, dann kommt bei Erfolg die Inventurseite, bei Miss- |
387 # | bleibt man auf der Neuanlegen-Seite |
388 # | |
389 # | Dummerweise kann ich aber die Kontextbuttons erst dann anzeigen, |
390 # | wenn ich den Ausgang der Aktion kenne. Daher wird zuerst die Aktion |
391 # | ausgeführt, welche aber keinen HTML-Code ausgeben darf. |
392 # `----------------------------------------------------------------------'
395 @cmk.gui.pages.register("wato")
396 def page_handler():
397 initialize_wato_html_head()
399 if not config.wato_enabled:
400 raise MKGeneralException(_("WATO is disabled. Please set <tt>wato_enabled = True</tt>"
401 " in your <tt>multisite.mk</tt> if you want to use WATO."))
403 if cmk.is_managed_edition() and not managed.is_provider(config.current_customer):
404 raise MKGeneralException(_("Check_MK can only be configured on "
405 "the managers central site."))
407 current_mode = html.var("mode") or "main"
408 mode_permissions, mode_class = get_mode_permission_and_class(current_mode)
410 display_options.load_from_html()
412 if display_options.disabled(display_options.N):
413 html.add_body_css_class("inline")
415 # If we do an action, we aquire an exclusive lock on the complete WATO.
416 if html.is_transaction():
417 watolib.lock_exclusive()
419 try:
420 init_wato_datastructures(with_wato_lock=not html.is_transaction())
421 except:
422 # Snapshot must work in any case
423 if current_mode == 'snapshot':
424 pass
425 else:
426 raise
428 # Check general permission for this mode
429 if mode_permissions != None and not config.user.may("wato.seeall"):
430 ensure_mode_permissions(mode_permissions)
432 mode = mode_class()
434 # Do actions (might switch mode)
435 action_message = None
436 if html.is_transaction():
437 try:
438 config.user.need_permission("wato.edit")
440 # Even if the user has seen this mode because auf "seeall",
441 # he needs an explicit access permission for doing changes:
442 if config.user.may("wato.seeall"):
443 if mode_permissions:
444 ensure_mode_permissions(mode_permissions)
446 if watolib.is_read_only_mode_enabled() and not watolib.may_override_read_only_mode():
447 raise MKUserError(None, watolib.read_only_message())
449 result = mode.action()
450 if isinstance(result, tuple):
451 newmode, action_message = result
452 else:
453 newmode = result
455 # If newmode is False, then we shall immediately abort.
456 # This is e.g. the case, if the page outputted non-HTML
457 # data, such as a tarball (in the export function). We must
458 # be sure not to output *any* further data in that case.
459 if newmode == False:
460 return
462 # if newmode is not None, then the mode has been changed
463 elif newmode != None:
464 if newmode == "": # no further information: configuration dialog, etc.
465 if action_message:
466 html.message(action_message)
467 wato_html_footer()
468 return
469 mode_permissions, mode_class = get_mode_permission_and_class(newmode)
470 current_mode = newmode
471 mode = mode_class()
472 html.set_var("mode", newmode) # will be used by makeuri
474 # Check general permissions for the new mode
475 if mode_permissions != None and not config.user.may("wato.seeall"):
476 for pname in mode_permissions:
477 if '.' not in pname:
478 pname = "wato." + pname
479 config.user.need_permission(pname)
481 except MKUserError, e:
482 action_message = "%s" % e
483 html.add_user_error(e.varname, action_message)
485 except MKAuthException, e:
486 action_message = e.reason
487 html.add_user_error(None, e.reason)
489 wato_html_head(mode.title(),
490 show_body_start=display_options.enabled(display_options.H),
491 show_top_heading=display_options.enabled(display_options.T))
493 if display_options.enabled(display_options.B):
494 # Show contexts buttons
495 html.begin_context_buttons()
496 mode.buttons()
497 for inmode, buttontext, target in extra_buttons:
498 if inmode == current_mode:
499 if hasattr(target, '__call__'):
500 target = target()
501 if not target:
502 continue
503 if target[0] == '/' or target.startswith('../') or '://' in target:
504 html.context_button(buttontext, target)
505 else:
506 html.context_button(buttontext, watolib.folder_preserving_link([("mode", target)]))
507 html.end_context_buttons()
509 if not html.is_transaction() or (watolib.is_read_only_mode_enabled() and watolib.may_override_read_only_mode()):
510 _show_read_only_warning()
512 # Show outcome of action
513 if html.has_user_errors():
514 html.show_error(action_message)
515 elif action_message:
516 html.message(action_message)
518 # Show content
519 mode.handle_page()
521 if watolib.is_sidebar_reload_needed():
522 html.reload_sidebar()
524 if config.wato_use_git and html.is_transaction():
525 watolib.do_git_commit()
527 wato_html_footer(display_options.enabled(display_options.Z),
528 display_options.enabled(display_options.H))
531 def get_mode_permission_and_class(mode_name):
532 mode_class = mode_registry.get(mode_name, ModeNotImplemented)
533 mode_permissions = mode_class.permissions()
535 if mode_class is None:
536 raise MKGeneralException(_("No such WATO module '<tt>%s</tt>'") % mode_name)
538 if callable(mode_class):
539 raise MKGeneralException(_("Deprecated WATO module: Implemented as function. "
540 "This needs to be refactored as WatoMode child class."))
542 if mode_permissions != None and not config.user.may("wato.use"):
543 raise MKAuthException(_("You are not allowed to use WATO."))
545 return mode_permissions, mode_class
548 def ensure_mode_permissions(mode_permissions):
549 for pname in mode_permissions:
550 if '.' not in pname:
551 pname = "wato." + pname
552 config.user.need_permission(pname)
555 def _show_read_only_warning():
556 if watolib.is_read_only_mode_enabled():
557 html.show_warning(watolib.read_only_message())
561 # .--Agent-Output--------------------------------------------------------.
562 # | _ _ ___ _ _ |
563 # | / \ __ _ ___ _ __ | |_ / _ \ _ _| |_ _ __ _ _| |_ |
564 # | / _ \ / _` |/ _ \ '_ \| __|____| | | | | | | __| '_ \| | | | __| |
565 # | / ___ \ (_| | __/ | | | ||_____| |_| | |_| | |_| |_) | |_| | |_ |
566 # | /_/ \_\__, |\___|_| |_|\__| \___/ \__,_|\__| .__/ \__,_|\__| |
567 # | |___/ |_| |
568 # +----------------------------------------------------------------------+
569 # | Page for downloading the current agent output / SNMP walk of a host |
570 # '----------------------------------------------------------------------'
571 # TODO: This feature is used exclusively from the GUI. Why is the code in
572 # wato.py? The only reason is because the WATO automation is used. Move
573 # to better location.
575 class AgentOutputPage(object):
576 __metaclass__ = abc.ABCMeta
578 def __init__(self):
579 super(AgentOutputPage, self).__init__()
580 self._from_vars()
583 def _from_vars(self):
584 config.user.need_permission("wato.download_agent_output")
586 host_name = html.var("host")
587 if not host_name:
588 raise MKGeneralException(_("The host is missing."))
590 ty = html.var("type")
591 if ty not in [ "walk", "agent" ]:
592 raise MKGeneralException(_("Invalid type specified."))
593 self._ty = ty
595 self._back_url = html.get_url_input("back_url")
597 init_wato_datastructures(with_wato_lock=True)
599 host = watolib.Folder.current().host(host_name)
600 if not host:
601 raise MKGeneralException(_("Host is not managed by WATO. "
602 "Click <a href=\"%s\">here</a> to go back.") %
603 html.escape_attribute(self._back_url))
604 host.need_permission("read")
605 self._host = host
607 self._job = FetchAgentOutputBackgroundJob(self._host.site_id(), self._host.name(), self._ty)
610 @abc.abstractmethod
611 def page(self):
612 pass
615 @staticmethod
616 def file_name(site_id, host_name, ty):
617 return "%s-%s-%s.txt" % (site_id, host_name, ty)
620 class PageFetchAgentOutput(AgentOutputPage):
621 def page(self):
622 html.header(_("%s: Download agent output") % self._host.name(),
623 stylesheets=["status", "pages"])
625 html.begin_context_buttons()
626 if self._back_url:
627 html.context_button(_("Back"), self._back_url, "back")
628 html.end_context_buttons()
630 self._action()
632 if html.has_var("_start"):
633 try:
634 self._job.start()
635 except background_job.BackgroundJobAlreadyRunning:
636 pass
638 self._show_status(self._job)
640 html.footer()
643 def _action(self):
644 if not html.transaction_valid():
645 return
647 action_handler = gui_background_job.ActionHandler()
649 if action_handler.handle_actions() and action_handler.did_delete_job():
650 html.response.http_redirect(html.makeuri_contextless([
651 ("host", self._host.name()),
652 ("type", self._ty),
653 ("back_url", self._back_url),
657 def _show_status(self, job):
658 job_snapshot = job.get_status_snapshot()
660 if job_snapshot.is_running():
661 html.h3(_("Current status of process"))
662 html.immediate_browser_redirect(0.8, html.makeuri([]))
663 elif job.exists():
664 html.h3(_("Result of last process"))
666 job_manager = gui_background_job.GUIBackgroundJobManager()
667 job_manager.show_job_details_from_snapshot(job_snapshot=job_snapshot)
669 # TODO: Clean this up! We would like to use the cmk.gui.pages.register() decorator instead
670 # of this
671 cmk.gui.pages.register_page_handler("fetch_agent_output", lambda: PageFetchAgentOutput().page())
674 @gui_background_job.job_registry.register
675 class FetchAgentOutputBackgroundJob(WatoBackgroundJob):
676 job_prefix = "agent-output-"
677 gui_title = _("Fetch agent output")
679 def __init__(self, site_id, host_name, ty):
680 self._site_id = site_id
681 self._host_name = host_name
682 self._ty = ty
684 job_id = "%s%s-%s-%s" % (self.job_prefix, site_id, host_name, ty)
685 title = _("Fetching %s of %s / %s") % (ty, site_id, host_name)
686 super(FetchAgentOutputBackgroundJob, self).__init__(job_id, title=title)
688 self.set_function(self._fetch_agent_output)
691 def _fetch_agent_output(self, job_interface):
692 job_interface.send_progress_update(_("Fetching '%s'...") % self._ty)
694 success, output, agent_data = watolib.check_mk_automation(self._site_id, "get-agent-output",
695 [self._host_name, self._ty])
697 if not success:
698 job_interface.send_progress_update(_("Failed: %s") % output)
700 preview_filepath = os.path.join(job_interface.get_work_dir(),
701 AgentOutputPage.file_name(self._site_id, self._host_name, self._ty))
702 store.save_file(preview_filepath, agent_data)
704 download_url = html.makeuri_contextless([
705 ("host", self._host_name),
706 ("type", self._ty)
707 ], filename="download_agent_output.py")
709 button = html.render_icon_button(download_url, _("Download"), "agent_output")
710 job_interface.send_progress_update(_("Finished. Click on the icon to download the data."))
711 job_interface.send_result_message(_("%s Finished.") % button)
714 class PageDownloadAgentOutput(AgentOutputPage):
715 def page(self):
716 file_name = self.file_name(self._host.site_id(), self._host.name(), self._ty)
718 html.set_output_format("text")
719 html.response.set_http_header("Content-Disposition", "Attachment; filename=%s" % file_name)
721 preview_filepath = os.path.join(self._job.get_work_dir(), file_name)
722 html.write(file(preview_filepath).read())
724 cmk.gui.pages.register_page_handler("download_agent_output", lambda: PageDownloadAgentOutput().page())
728 # .--Network Scan--------------------------------------------------------.
729 # | _ _ _ _ ____ |
730 # | | \ | | ___| |___ _____ _ __| | __ / ___| ___ __ _ _ __ |
731 # | | \| |/ _ \ __\ \ /\ / / _ \| '__| |/ / \___ \ / __/ _` | '_ \ |
732 # | | |\ | __/ |_ \ V V / (_) | | | < ___) | (_| (_| | | | | |
733 # | |_| \_|\___|\__| \_/\_/ \___/|_| |_|\_\ |____/ \___\__,_|_| |_| |
734 # | |
735 # +----------------------------------------------------------------------+
736 # | The WATO folders network scan for new hosts. |
737 # '----------------------------------------------------------------------'
739 # Executed by the multisite cron job once a minute. Is only executed in the
740 # master site. Finds the next folder to scan and starts it via WATO
741 # automation. The result is written to the folder in the master site.
742 def execute_network_scan_job():
743 init_wato_datastructures(with_wato_lock=True)
745 if watolib.is_wato_slave_site():
746 return # Don't execute this job on slaves.
748 folder = find_folder_to_scan()
749 if not folder:
750 return # Nothing to do.
752 # We need to have the context of the user. The jobs are executed when
753 # config.set_user_by_id() has not been executed yet. So there is no user context
754 # available. Use the run_as attribute from the job config and revert
755 # the previous state after completion.
756 old_user = config.user.id
757 run_as = folder.attribute("network_scan")["run_as"]
758 if not userdb.user_exists(run_as):
759 raise MKGeneralException(_("The user %s used by the network "
760 "scan of the folder %s does not exist.") % (run_as, folder.title()))
761 config.set_user_by_id(folder.attribute("network_scan")["run_as"])
763 result = {
764 "start" : time.time(),
765 "end" : True, # means currently running
766 "state" : None,
767 "output" : "The scan is currently running.",
770 # Mark the scan in progress: Is important in case the request takes longer than
771 # the interval of the cron job (1 minute). Otherwise the scan might be started
772 # a second time before the first one finished.
773 save_network_scan_result(folder, result)
775 try:
776 if config.site_is_local(folder.site_id()):
777 found = watolib.do_network_scan(folder)
778 else:
779 found = watolib.do_remote_automation(config.site(folder.site_id()), "network-scan",
780 [("folder", folder.path())])
782 if not isinstance(found, list):
783 raise MKGeneralException(_("Received an invalid network scan result: %r") % found)
785 add_scanned_hosts_to_folder(folder, found)
787 result.update({
788 "state" : True,
789 "output" : _("The network scan found %d new hosts.") % len(found),
791 except Exception, e:
792 result.update({
793 "state" : False,
794 "output" : _("An exception occured: %s") % e,
796 logger.error("Exception in network scan:\n%s" % (traceback.format_exc()))
798 result["end"] = time.time()
800 save_network_scan_result(folder, result)
802 if old_user:
803 config.set_user_by_id(old_user)
806 # Find the folder which network scan is longest waiting and return the
807 # folder object.
808 def find_folder_to_scan():
809 folder_to_scan = None
810 for folder in watolib.Folder.all_folders().itervalues():
811 scheduled_time = folder.next_network_scan_at()
812 if scheduled_time != None and scheduled_time < time.time():
813 if folder_to_scan == None:
814 folder_to_scan = folder
815 elif folder_to_scan.next_network_scan_at() > folder.next_network_scan_at():
816 folder_to_scan = folder
817 return folder_to_scan
820 def add_scanned_hosts_to_folder(folder, found):
821 network_scan_properties = folder.attribute("network_scan")
823 translation = network_scan_properties.get("translate_names", {})
825 entries = []
826 for host_name, ipaddress in found:
827 host_name = cmk.translations.translate_hostname(translation, host_name)
829 attrs = {}
830 if "tag_criticality" in network_scan_properties:
831 attrs["tag_criticality"] = network_scan_properties.get("tag_criticality", "offline")
833 if network_scan_properties.get("set_ipaddress", True):
834 attrs["ipaddress"] = ipaddress
836 if not watolib.Host.host_exists(host_name):
837 entries.append((host_name, attrs, None))
839 watolib.lock_exclusive()
840 folder.create_hosts(entries)
841 folder.save()
842 watolib.unlock_exclusive()
845 def save_network_scan_result(folder, result):
846 # Reload the folder, lock WATO before to protect against concurrency problems.
847 watolib.lock_exclusive()
849 # A user might have changed the folder somehow since starting the scan. Load the
850 # folder again to get the current state.
851 write_folder = watolib.Folder.folder(folder.path())
852 write_folder.set_attribute("network_scan_result", result)
853 write_folder.save()
855 watolib.unlock_exclusive()
860 # .--Plugins-------------------------------------------------------------.
861 # | ____ _ _ |
862 # | | _ \| |_ _ __ _(_)_ __ ___ |
863 # | | |_) | | | | |/ _` | | '_ \/ __| |
864 # | | __/| | |_| | (_| | | | | \__ \ |
865 # | |_| |_|\__,_|\__, |_|_| |_|___/ |
866 # | |___/ |
867 # +----------------------------------------------------------------------+
868 # | Prepare plugin-datastructures and load WATO plugins |
869 # '----------------------------------------------------------------------'
871 modes = {}
872 # TODO: Drop this and probably replace with a hook at button rendering?
873 extra_buttons = []
875 loaded_with_language = False
876 def load_plugins(force):
877 global loaded_with_language
878 if loaded_with_language == cmk.gui.i18n.get_current_language() and not force:
879 return
881 # Reset global vars
882 del extra_buttons[:]
884 # Initialize watolib things which are needed before loading the WATO plugins.
885 # This also loads the watolib plugins.
886 watolib.load_watolib_plugins()
888 # Declare WATO-specific permissions
889 config.declare_permission_section("wato", _("WATO - Check_MK's Web Administration Tool"))
891 config.declare_permission("wato.use",
892 _("Use WATO"),
893 _("This permissions allows users to use WATO - Check_MK's "
894 "Web Administration Tool. Without this "
895 "permission all references to WATO (buttons, links, "
896 "snapins) will be invisible."),
897 [ "admin", "user" ])
899 config.declare_permission("wato.edit",
900 _("Make changes, perform actions"),
901 _("This permission is needed in order to make any "
902 "changes or perform any actions at all. "
903 "Without this permission, the user is only "
904 "able to view data, and that only in modules he "
905 "has explicit permissions for."),
906 [ "admin", "user" ])
908 config.declare_permission("wato.seeall",
909 _("Read access to all modules"),
910 _("When this permission is set then the user sees "
911 "also such modules he has no explicit "
912 "access to (see below)."),
913 [ "admin", ])
915 config.declare_permission("wato.activate",
916 _("Activate Configuration"),
917 _("This permission is needed for activating the "
918 "current configuration (and thus rewriting the "
919 "monitoring configuration and restart the monitoring daemon.)"),
920 [ "admin", "user", ])
922 config.declare_permission("wato.activateforeign",
923 _("Activate Foreign Changes"),
924 _("When several users work in parallel with WATO then "
925 "several pending changes of different users might pile up "
926 "before changes are activate. Only with this permission "
927 "a user will be allowed to activate the current configuration "
928 "if this situation appears."),
929 [ "admin", ])
931 config.declare_permission("wato.auditlog",
932 _("Audit Log"),
933 _("Access to the historic audit log. "
934 "The currently pending changes can be seen by all users "
935 "with access to WATO."),
936 [ "admin", ])
938 config.declare_permission("wato.clear_auditlog",
939 _("Clear audit Log"),
940 _("Clear the entries of the audit log. To be able to clear the audit log "
941 "a user needs the generic WATO permission \"Make changes, perform actions\", "
942 "the \"View audit log\" and this permission."),
943 [ "admin", ])
945 config.declare_permission("wato.hosts",
946 _("Host management"),
947 _("Access to the management of hosts and folders. This "
948 "module has some additional permissions (see below)."),
949 [ "admin", "user" ])
951 config.declare_permission("wato.edit_hosts",
952 _("Modify existing hosts"),
953 _("Modify the properties of existing hosts. Please note: "
954 "for the management of services (inventory) there is "
955 "a separate permission (see below)"),
956 [ "admin", "user" ])
958 config.declare_permission("wato.parentscan",
959 _("Perform network parent scan"),
960 _("This permission is neccessary for performing automatic "
961 "scans for network parents of hosts (making use of traceroute). "
962 "Please note, that for actually modifying the parents via the "
963 "scan and for the creation of gateway hosts proper permissions "
964 "for host and folders are also neccessary."),
965 [ "admin", "user" ])
967 config.declare_permission("wato.move_hosts",
968 _("Move existing hosts"),
969 _("Move existing hosts to other folders. Please also add the permission "
970 "<i>Modify existing hosts</i>."),
971 [ "admin", "user" ])
973 config.declare_permission("wato.rename_hosts",
974 _("Rename existing hosts"),
975 _("Rename existing hosts. Please also add the permission "
976 "<i>Modify existing hosts</i>."),
977 [ "admin" ])
979 config.declare_permission("wato.manage_hosts",
980 _("Add & remove hosts"),
981 _("Add hosts to the monitoring and remove hosts "
982 "from the monitoring. Please also add the permission "
983 "<i>Modify existing hosts</i>."),
984 [ "admin", "user" ])
986 config.declare_permission("wato.diag_host",
987 _("Host Diagnostic"),
988 _("Check whether or not the host is reachable, test the different methods "
989 "a host can be accessed, for example via agent, SNMPv1, SNMPv2 to find out "
990 "the correct monitoring configuration for that host."),
991 [ "admin", "user" ])
994 config.declare_permission("wato.clone_hosts",
995 _("Clone hosts"),
996 _("Clone existing hosts to create new ones from the existing one."
997 "Please also add the permission <i>Add & remove hosts</i>."),
998 [ "admin", "user" ])
1000 config.declare_permission("wato.random_hosts",
1001 _("Create random hosts"),
1002 _("The creation of random hosts is a facility for test and development "
1003 "and disabled by default. It allows you to create a number of random "
1004 "hosts and thus simulate larger environments."),
1005 [ ])
1007 config.declare_permission("wato.update_dns_cache",
1008 _("Update DNS Cache"),
1009 _("Updating the DNS cache is neccessary in order to reflect IP address "
1010 "changes in hosts that are configured without an explicit address."),
1011 [ "admin", "user" ])
1013 config.declare_permission("wato.services",
1014 _("Manage services"),
1015 _("Do inventory and service configuration on existing hosts."),
1016 [ "admin", "user" ])
1018 config.declare_permission("wato.edit_folders",
1019 _("Modify existing folders"),
1020 _("Modify the properties of existing folders."),
1021 [ "admin", "user" ])
1023 config.declare_permission("wato.manage_folders",
1024 _("Add & remove folders"),
1025 _("Add new folders and delete existing folders. If a folder to be deleted contains hosts then "
1026 "the permission to delete hosts is also required."),
1027 [ "admin", "user" ])
1029 config.declare_permission("wato.passwords",
1030 _("Password management"),
1031 _("This permission is needed for the module <i>Passwords</i>."),
1032 [ "admin", "user" ])
1034 config.declare_permission("wato.edit_all_passwords",
1035 _("Write access to all passwords"),
1036 _("Without this permission, users can only edit passwords which are shared with a contact "
1037 "group they are member of. This permission grants full access to all passwords."),
1038 [ "admin" ])
1040 config.declare_permission("wato.see_all_folders",
1041 _("Read access to all hosts and folders"),
1042 _("Users without this permissions can only see folders with a contact group they are in."),
1043 [ "admin" ])
1045 config.declare_permission("wato.all_folders",
1046 _("Write access to all hosts and folders"),
1047 _("Without this permission, operations on folders can only be done by users that are members of "
1048 "one of the folders contact groups. This permission grants full access to all folders and hosts."),
1049 [ "admin" ])
1051 config.declare_permission("wato.hosttags",
1052 _("Manage host tags"),
1053 _("Create, remove and edit host tags. Removing host tags also might remove rules, "
1054 "so this permission should not be available to normal users. "),
1055 [ "admin" ])
1057 config.declare_permission("wato.global",
1058 _("Global settings"),
1059 _("Access to the module <i>Global settings</i>"),
1060 [ "admin", ])
1062 config.declare_permission("wato.rulesets",
1063 _("Rulesets"),
1064 _("Access to the module for managing Check_MK rules. Please note that a user can only "
1065 "manage rules in folders he has permissions to. "),
1066 [ "admin", "user" ])
1068 config.declare_permission("wato.groups",
1069 _("Host & Service Groups"),
1070 _("Access to the modules for managing host and service groups."),
1071 [ "admin", ])
1073 config.declare_permission("wato.timeperiods",
1074 _("Timeperiods"),
1075 _("Access to the module <i>Timeperiods</i>"),
1076 [ "admin", ])
1078 config.declare_permission("wato.sites",
1079 _("Site management"),
1080 _("Access to the module for managing connections to remote monitoring sites."),
1081 [ "admin", ])
1083 config.declare_permission("wato.automation",
1084 _("Site remote automation"),
1085 _("This permission is needed for a remote administration of the site "
1086 "as a distributed WATO slave."),
1087 [ "admin", ])
1089 config.declare_permission("wato.users",
1090 _("User management"),
1091 _("This permission is needed for the modules <b>Users</b>, <b>Roles</b> and <b>Contact Groups</b>"),
1092 [ "admin", ])
1094 config.declare_permission("wato.notifications",
1095 _("Notification configuration"),
1096 _("This permission is needed for the new rule based notification configuration via the WATO module <i>Notifications</i>."),
1097 [ "admin", ])
1099 config.declare_permission("wato.snapshots",
1100 _("Manage snapshots"),
1101 _("Access to the module <i>Snaphsots</i>. Please note: a user with "
1102 "write access to this module "
1103 "can make arbitrary changes to the configuration by restoring uploaded snapshots."),
1104 [ "admin", ])
1106 config.declare_permission("wato.backups",
1107 _("Backup & Restore"),
1108 _("Access to the module <i>Site backup</i>. Please note: a user with "
1109 "write access to this module "
1110 "can make arbitrary changes to the configuration by restoring uploaded snapshots."),
1111 [ "admin", ])
1113 config.declare_permission("wato.pattern_editor",
1114 _("Logfile Pattern Analyzer"),
1115 _("Access to the module for analyzing and validating logfile patterns."),
1116 [ "admin", "user" ])
1118 config.declare_permission("wato.icons",
1119 _("Manage Custom Icons"),
1120 _("Upload or delete custom icons"),
1121 [ "admin" ])
1123 config.declare_permission("wato.custom_attributes",
1124 _("Manage custom attributes"),
1125 _("Manage custom host- and user attributes"),
1126 [ "admin" ])
1128 config.declare_permission("wato.download_agents",
1129 _("Monitoring Agents"),
1130 _("Download the default Check_MK monitoring agents for Linux, "
1131 "Windows and other operating systems."),
1132 [ "admin", "user", "guest" ])
1134 config.declare_permission("wato.download_agent_output",
1135 _("Download Agent Output / SNMP Walks"),
1136 _("Allows to download the current agent output or SNMP walks of the monitored hosts."),
1137 [ "admin" ])
1139 config.declare_permission("wato.set_read_only",
1140 _("Set WATO to read only mode for other users"),
1141 _("Prevent other users from making modifications to WATO."),
1142 [ "admin" ])
1144 config.declare_permission("wato.analyze_config",
1145 _("Access the best analyze configuration functionality provided by WATO"),
1146 _("WATO has a module that gives you hints on how to tune your Check_MK installation."),
1147 [ "admin" ])
1149 config.declare_permission("wato.add_or_modify_executables",
1150 _("Can add or modify executables"),
1151 _("There are different places in Check_MK where an admin can use the GUI to add "
1152 "executable code to Check_MK. For example when configuring "
1153 "datasource programs, the user inserts a command line for gathering monitoring data. "
1154 "This command line is then executed during monitoring by Check_MK. Another example is "
1155 "the upload of extension packages (MKPs). All these functions have in "
1156 "common that the user provides data that is executed by Check_MK. "
1157 "If you want to ensure that your WATO users cannot \"inject\" arbitrary executables "
1158 "into your Check_MK installation, you only need to remove this permission for them. "
1159 "This permission is needed in addition to the other component related permissions. "
1160 "For example you need the <tt>wato.rulesets</tt> permission together with this "
1161 "permission to be able to configure rulesets where bare command lines are "
1162 "configured."),
1163 [ "admin" ])
1165 config.declare_permission("wato.service_discovery_to_undecided",
1166 _("Service discovery: Move to undecided services"),
1167 _("Service discovery: Move to undecided services"),
1168 [ "admin", "user" ])
1170 config.declare_permission("wato.service_discovery_to_monitored",
1171 _("Service discovery: Move to monitored services"),
1172 _("Service discovery: Move to monitored services"),
1173 [ "admin", "user" ])
1175 config.declare_permission("wato.service_discovery_to_ignored",
1176 _("Service discovery: Disabled services"),
1177 _("Service discovery: Disabled services"),
1178 [ "admin", "user" ])
1180 config.declare_permission("wato.service_discovery_to_removed",
1181 _("Service discovery: Remove services"),
1182 _("Service discovery: Remove services"),
1183 [ "admin", "user" ])
1185 utils.load_web_plugins("wato", globals())
1187 if modes:
1188 raise MKGeneralException(_("Deprecated WATO modes found: %r. "
1189 "They need to be refactored to new API.") % modes.keys())
1191 # This must be set after plugin loading to make broken plugins raise
1192 # exceptions all the time and not only the first time (when the plugins
1193 # are loaded).
1194 loaded_with_language = cmk.gui.i18n.get_current_language()