2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
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.
30 import cmk
.gui
.config
as config
31 import cmk
.gui
.watolib
as watolib
32 import cmk
.gui
.hooks
as hooks
33 import cmk
.gui
.userdb
as userdb
34 from cmk
.gui
.i18n
import _
35 from cmk
.gui
.globals import html
36 from cmk
.gui
.htmllib
import HTML
37 from cmk
.gui
.valuespec
import (
60 from cmk
.gui
.exceptions
import MKUserError
62 from cmk
.gui
.plugins
.wato
import (
63 HostAttributeTopicBasicSettings
,
64 HostAttributeTopicNetworkScan
,
65 HostAttributeTopicAddress
,
66 HostAttributeTopicManagementBoard
,
67 HostAttributeTopicMetaData
,
68 ABCHostAttributeValueSpec
,
69 ABCHostAttributeNagiosText
,
70 host_attribute_registry
,
78 @host_attribute_registry.register
79 class HostAttributeAlias(ABCHostAttributeNagiosText
):
81 return HostAttributeTopicBasicSettings
86 def nagios_name(self
):
93 return _("A comment or description of this host")
95 def show_in_folder(self
):
99 @host_attribute_registry.register
100 class HostAttributeIPv4Address(ABCHostAttributeValueSpec
):
102 return HostAttributeTopicAddress
107 def show_in_folder(self
):
110 def depends_on_tags(self
):
115 title
=_("IPv4 Address"),
116 help=_("In case the name of the host is not resolvable via <tt>/etc/hosts</tt> "
117 "or DNS by your monitoring server, you can specify an explicit IP "
118 "address or a resolvable DNS name of the host here.<br> <b>Notes</b>:<br> "
119 "1. If you leave this attribute empty, hostname resolution will be done when "
120 "you activate the configuration. "
121 "Check_MKs builtin DNS cache is activated per default in the global "
122 "configuration to speed up the activation process. The cache is normally "
123 "updated daily with a cron job. You can manually update the cache with the "
124 "command <tt>cmk -v --update-dns-cache</tt>.<br>"
125 "2. If you enter a DNS name here, the DNS resolution will be carried out "
126 "each time the host is checked. Check_MKs DNS cache will NOT be queried. "
127 "Use this only for hosts with dynamic IP addresses."),
129 allow_ipv6_address
=False,
133 @host_attribute_registry.register
134 class HostAttributeIPv6Address(ABCHostAttributeValueSpec
):
136 return HostAttributeTopicAddress
141 def show_in_folder(self
):
144 def depends_on_tags(self
):
149 title
=_("IPv6 Address"),
150 help=_("In case the name of the host is not resolvable via <tt>/etc/hosts</tt> "
151 "or DNS by your monitoring server, you can specify an explicit IPv6 "
152 "address or a resolvable DNS name of the host here.<br> <b>Notes</b>:<br> "
153 "1. If you leave this attribute empty, hostname resolution will be done when "
154 "you activate the configuration. "
155 "Check_MKs builtin DNS cache is activated per default in the global "
156 "configuration to speed up the activation process. The cache is normally "
157 "updated daily with a cron job. You can manually update the cache with the "
158 "command <tt>cmk -v --update-dns-cache</tt>.<br>"
159 "2. If you enter a DNS name here, the DNS resolution will be carried out "
160 "each time the host is checked. Check_MKs DNS cache will NOT be queried. "
161 "Use this only for hosts with dynamic IP addresses."),
163 allow_ipv4_address
=False,
167 @host_attribute_registry.register
168 class HostAttributeAdditionalIPv4Addresses(ABCHostAttributeValueSpec
):
170 return HostAttributeTopicAddress
173 return "additional_ipv4addresses"
175 def show_in_table(self
):
178 def show_in_folder(self
):
181 def depends_on_tags(self
):
188 allow_ipv6_address
=False,
190 title
=_("Additional IPv4 addresses"),
191 help=_("Here you can specify additional IPv4 addresses. "
192 "These can be used in some active checks like ICMP."),
196 @host_attribute_registry.register
197 class HostAttributeAdditionalIPv6Addresses(ABCHostAttributeValueSpec
):
199 return HostAttributeTopicAddress
202 return "additional_ipv6addresses"
204 def show_in_table(self
):
207 def show_in_folder(self
):
210 def depends_on_tags(self
):
217 allow_ipv4_address
=False,
219 title
=_("Additional IPv6 addresses"),
220 help=_("Here you can specify additional IPv6 addresses. "
221 "These can be used in some active checks like ICMP."),
225 @host_attribute_registry.register
226 class HostAttributeSNMPCommunity(ABCHostAttributeValueSpec
):
228 return HostAttributeTopicBasicSettings
231 return "snmp_community"
233 def show_in_table(self
):
236 def show_in_folder(self
):
239 def depends_on_tags(self
):
243 return SNMPCredentials(
244 help = _("Using this option you can configure the community which should be used when "
245 "contacting this host via SNMP v1/v2 or v3. It is possible to configure the SNMP community by "
246 "using the <a href=\"%s\">SNMP Communities</a> ruleset, but when you configure "
247 "a community here, this will override the community defined by the rules.") % \
248 "wato.py?mode=edit_ruleset&varname=snmp_communities",
249 default_value
= None,
253 @host_attribute_registry.register
254 class HostAttributeParents(ABCHostAttributeValueSpec
):
259 return HostAttributeTopicBasicSettings
261 def show_in_table(self
):
264 def show_in_folder(self
):
268 return ListOfStrings(
269 valuespec
=ConfigHostname(),
271 help=_("Parents are used to configure the reachability of hosts by the "
272 "monitoring server. A host is considered to be <b>unreachable</b> if all "
273 "of its parents are unreachable or down. Unreachable hosts will not be "
274 "actively monitored.<br><br><b>Clusters</b> automatically configure all "
275 "of their nodes as parents, but only if you do not configure parents "
276 "manually.<br><br>In a distributed setup make sure that the host and all "
277 "of its parents are monitored by the same site."),
278 orientation
="horizontal",
281 def is_visible(self
, for_what
):
282 return for_what
!= "cluster"
284 def to_nagios(self
, value
):
286 return ",".join(value
)
288 def nagios_name(self
):
291 def paint(self
, value
, hostname
):
293 html
.render_a(hn
, "wato.py?" + html
.urlencode_vars([("mode", "edit_host"),
294 ("host", hn
)])) for hn
in value
296 return "", HTML(", ").join(parts
)
299 def validate_host_parents(host
):
300 for parent_name
in host
.parents():
301 if parent_name
== host
.name():
303 None, _("You configured the host to be it's own parent, which is not allowed."))
305 parent
= watolib
.Host
.host(parent_name
)
309 _("You defined the non-existing host '%s' as a parent.") % parent_name
)
311 if host
.site_id() != parent
.site_id():
314 _("The parent '%s' is monitored on site '%s' while the host itself "
315 "is monitored on site '%s'. Both must be monitored on the same site. Remember: The parent/child "
316 "relation is used to describe the reachability of hosts by one monitoring daemon."
317 ) % (parent_name
, parent
.site_id(), host
.site_id()))
320 hooks
.register_builtin('validate-host', validate_host_parents
)
323 @host_attribute_registry.register
324 class HostAttributeNetworkScan(ABCHostAttributeValueSpec
):
326 return "network_scan"
329 return config
.user
.may("wato.manage_hosts")
332 return HostAttributeTopicNetworkScan
334 def show_in_table(self
):
337 def show_in_form(self
):
340 def show_in_folder(self
):
343 def show_in_host_search(self
):
346 def show_inherited_value(self
):
351 elements
=self
._network
_scan
_elements
,
352 title
=_("Network Scan"),
353 help=_("For each folder an automatic network scan can be configured. It will "
354 "try to detect new hosts in the configured IP ranges by sending pings "
355 "to each IP address to check whether or not a host is using this ip "
356 "address. Each new found host will be added to the current folder by "
357 "it's hostname, when resolvable via DNS, or by it's IP address."),
358 optional_keys
=["max_parallel_pings", "translate_names"],
359 default_text
=_("Not configured."),
362 def _network_scan_elements(self
):
367 title
=_("IP ranges to scan"),
368 add_label
=_("Add new IP range"),
369 text_if_empty
=_("No IP range configured"),
374 title
=_("IP ranges to exclude"),
375 add_label
=_("Add new IP range"),
376 text_if_empty
=_("No exclude range configured"),
381 title
=_("Scan interval"),
382 display
=["days", "hours"],
383 default_value
=60 * 60 * 24,
384 minvalue
=3600, # 1 hour
389 TimeofdayRange(allow_empty
=False,),
390 title
=_("Time allowed"),
391 help=_("Limit the execution of the scan to this time range."),
393 style
=ListOf
.Style
.FLOATING
,
395 default_value
=[((0, 0), (24, 0))],
397 forth
=lambda x
: [x
] if isinstance(x
, tuple) else x
,
402 title
=_("Set IPv4 address"),
403 help=_("Whether or not to configure the found IP address as the IPv4 "
404 "address of the found hosts."),
409 elements
+= self
._optional
_tag
_criticality
_element
()
411 ("max_parallel_pings",
413 title
=_("Parallel pings to send"),
414 help=_("Set the maximum number of concurrent pings sent to target IP "
423 help=_("Execute the network scan in the Check_MK user context of the "
424 "choosen user. This user needs the permission to add new hosts "
426 choices
=self
._get
_all
_user
_ids
,
427 default_value
=lambda: config
.user
.id,
429 ("translate_names", HostnameTranslation(title
=_("Translate Hostnames"),)),
434 def _get_all_user_ids(self
):
435 return [(user_id
, "%s (%s)" % (user_id
, user
.get("alias", user_id
)))
436 for user_id
, user
in userdb
.load_users(lock
=False).items()]
438 def _get_criticality_choices(self
):
439 """Returns the current configuration of the tag_group criticality"""
440 tags
= cmk
.gui
.tags
.TagConfig()
441 tags
.parse_config(watolib
.TagConfigFile().load_for_reading())
442 criticality_group
= tags
.get_tag_group("criticality")
443 if not criticality_group
:
445 return criticality_group
.get_tag_choices()
447 def _optional_tag_criticality_element(self
):
448 """This element is optional. The user may have deleted the tag group criticality"""
449 tags
= cmk
.gui
.tags
.TagConfig()
450 tags
.parse_config(watolib
.TagConfigFile().load_for_reading())
451 criticality_group
= tags
.get_tag_group("criticality")
452 if not criticality_group
:
455 return [("tag_criticality",
457 title
=_("Set criticality host tag"),
458 help=_("Added hosts will be created as \"offline\" host by default. You "
459 "can change this option to activate monitoring of new hosts after "
460 "next activation of the configuration after the scan."),
461 choices
=self
._get
_criticality
_choices
,
462 default_value
="offline",
465 def _vs_ip_range(self
):
466 return CascadingDropdown(choices
=[
467 ("ip_range", _("IP-Range"),
470 IPv4Address(title
=_("From:"),),
471 IPv4Address(title
=_("To:"),),
473 orientation
="horizontal",
475 ("ip_network", _("IP Network"),
478 IPv4Address(title
=_("Network address:"),),
485 orientation
="horizontal",
487 ("ip_list", _("Explicit List of IP Addresses"),
489 valuespec
=IPv4Address(),
490 orientation
="horizontal",
492 ("ip_regex_list", _("List of patterns to exclude"),
494 valuespec
=RegExp(mode
=RegExp
.prefix
,),
495 orientation
="horizontal",
496 help=_("A list of regular expressions which are matched against the found "
497 "IP addresses to exclude them. The matched addresses are excluded."),
502 @host_attribute_registry.register
503 class HostAttributeNetworkScanResult(ABCHostAttributeValueSpec
):
505 return "network_scan_result"
508 return HostAttributeTopicNetworkScan
510 def show_in_table(self
):
513 def show_in_form(self
):
516 def show_in_folder(self
):
519 def show_in_host_search(self
):
522 def show_inherited_value(self
):
538 totext
=_("No scan has been started yet."),
554 totext
=_("No scan has finished yet."),
558 totext
="", # currently running
574 totext
="", # Not started or currently running
578 totext
=_("Succeeded"),
587 ("output", TextUnicode(title
=_("Output"),)),
589 title
=_("Last Scan Result"),
591 default_text
=_("No scan performed yet."),
595 @host_attribute_registry.register
596 class HostAttributeManagementAddress(ABCHostAttributeValueSpec
):
598 return "management_address"
601 return HostAttributeTopicManagementBoard
603 def show_in_table(self
):
606 def show_in_folder(self
):
612 help=_("Address (IPv4 or IPv6) or dns name under which the "
613 "management board can be reached. If this is not set, "
614 "the same address as that of the host will be used."),
619 @host_attribute_registry.register
620 class HostAttributeManagementProtocol(ABCHostAttributeValueSpec
):
622 return "management_protocol"
625 return HostAttributeTopicManagementBoard
627 def show_in_table(self
):
630 def show_in_folder(self
):
634 return DropdownChoice(
636 help=_("Specify the protocol used to connect to the management board."),
638 (None, _("No management board")),
641 #("ping", _("Ping-only"))
646 @host_attribute_registry.register
647 class HostAttributeManagementSNMPCommunity(ABCHostAttributeValueSpec
):
649 return "management_snmp_community"
652 return HostAttributeTopicManagementBoard
654 def show_in_table(self
):
657 def show_in_folder(self
):
661 return SNMPCredentials(
667 class IPMICredentials(Alternative
):
668 def __init__(self
, **kwargs
):
669 kwargs
["style"] = "dropdown"
670 kwargs
["elements"] = [
673 title
=_("No explicit credentials"),
678 super(IPMICredentials
, self
).__init
__(**kwargs
)
681 @host_attribute_registry.register
682 class HostAttributeManagementIPMICredentials(ABCHostAttributeValueSpec
):
684 return "management_ipmi_credentials"
687 return HostAttributeTopicManagementBoard
689 def show_in_table(self
):
692 def show_in_folder(self
):
696 return IPMICredentials(
697 title
=_("IPMI credentials"),
702 @host_attribute_registry.register
703 class HostAttributeSite(ABCHostAttributeValueSpec
):
708 return HostAttributeTopicBasicSettings
710 def show_in_table(self
):
713 def show_in_folder(self
):
718 title
=_("Monitored on site"),
719 help=_("Specify the site that should monitor this host."),
720 invalid_choice_error
=_("The configured site is not known to this site. In case you "
721 "are configuring in a distributed slave, this may be a host "
722 "monitored by another site. If you want to modify this "
723 "host, you will have to change the site attribute to the "
724 "local site. But this may make the host be monitored from "
728 def get_tag_groups(self
, value
):
732 if value
is not None:
733 return {"site": value
}
738 @host_attribute_registry.register
739 class HostAttributeLockedBy(ABCHostAttributeValueSpec
):
744 return HostAttributeTopicMetaData
746 def show_in_table(self
):
749 def show_in_form(self
):
752 def show_in_folder(self
):
755 def show_in_host_search(self
):
758 def show_inherited_value(self
):
772 class LockedByValuespec(Tuple
):
774 super(LockedByValuespec
, self
).__init
__(
775 orientation
="horizontal",
779 ID(title
=_("Program"),),
780 ID(title
=_("Connection ID"),),
782 title
=_("Locked by"),
783 help=_("The host is (partially) managed by an automatic data source like the "
784 "Dynamic Configuration."),
787 def value_to_text(self
, value
):
788 if not value
or not value
[1] or not value
[2]:
789 return _("Not locked")
790 return super(LockedByValuespec
, self
).value_to_text(value
)
793 @host_attribute_registry.register
794 class HostAttributeLockedAttributes(ABCHostAttributeValueSpec
):
796 return "locked_attributes"
799 return HostAttributeTopicMetaData
801 def show_in_table(self
):
804 def show_in_form(self
):
807 def show_in_folder(self
):
810 def show_in_host_search(self
):
813 def show_inherited_value(self
):
821 DropdownChoice(choices
=host_attribute_registry
.get_choices
),
822 title
=_("Locked attributes"),
823 text_if_empty
=_("Not locked"),
827 @host_attribute_registry.register
828 class HostAttributeMetaData(ABCHostAttributeValueSpec
):
833 return HostAttributeTopicMetaData
835 def show_in_table(self
):
838 def show_in_form(self
):
841 def show_in_folder(self
):
844 def show_in_host_search(self
):
847 def show_inherited_value(self
):
859 title
=_("Created at"),
863 totext
=_("Sometime before 1.6"),
870 default_value
=time
.time(),
876 title
=_("Created by"),
880 totext
=_("Someone before 1.6"),
883 title
=_("Created by"),
884 default_value
="unknown",
887 default_value
=config
.user
.id,
891 title
=_("Meta data"),
896 @host_attribute_registry.register
897 class HostAttributeLabels(ABCHostAttributeValueSpec
):
905 return HostAttributeTopicBasicSettings
908 return _("With the help of labels you can flexibly group your hosts in "
909 "order to refer to them later at other places in Check_MK, e.g. in rule chains. "
910 "A label always consists of a combination of key and value in the format "
911 "\"key:value\". A host can only have one value per key. Check_MK will not perform "
912 "any validation on the labels you use.")
914 def show_in_table(self
):
917 def show_in_folder(self
):
921 return Labels(world
=Labels
.World
.CONFIG
, label_source
=Labels
.Source
.EXPLICIT
)
923 def filter_matches(self
, crit
, value
, hostname
):
924 return set(value
).issuperset(set(crit
))