Module: check_mk
Branch: master
Commit: fc5181ab46f2ac989c9f60f94f10305c7bdb0710
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=fc5181ab46f2ac…
Author: Simon Betz <si(a)mathias-kettner.de>
Date: Tue Jan 30 09:56:14 2018 +0100
5626 win_wmi_updates: Inventory of Windows Update KBs
Change-Id: Ib34bf6e58c5b540c053ff53c38e429d90bcf16bd
---
.werks/5626 | 10 ++++++
agents/windows/plugins/mk_inventory.vbs | 9 +++++
inventory/win_wmi_updates | 60 +++++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)
diff --git a/.werks/5626 b/.werks/5626
new file mode 100644
index 0000000..eb2f555
--- /dev/null
+++ b/.werks/5626
@@ -0,0 +1,10 @@
+Title: win_wmi_updates: Inventory of Windows Update KBs
+Level: 1
+Component: inv
+Compatible: compat
+Edition: cre
+Version: 1.5.0i3
+Date: 1517302546
+Class: feature
+
+
diff --git a/agents/windows/plugins/mk_inventory.vbs b/agents/windows/plugins/mk_inventory.vbs
index 19f74fe..21788f9 100644
--- a/agents/windows/plugins/mk_inventory.vbs
+++ b/agents/windows/plugins/mk_inventory.vbs
@@ -309,6 +309,15 @@ Call startSection("win_wmi_software",124,timeUntil)
swVars = Array( "ProductName", "Publisher", "VersionString", "InstallDate", "Language")
Call SoftwareFromInstaller(swVars)
+' Windows Updates
+Call startSection("win_wmi_updates",44,timeUntil)
+Set objShell = WScript.CreateObject("WScript.Shell")
+Set objExecObject = objShell.Exec("wmic qfe get HotfixID,Description,InstalledOn /format:csv")
+Do While Not objExecObject.StdOut.AtEndOfStream
+ strText = objExecObject.StdOut.ReadLine()
+ outPut(strText)
+Loop
+
' Search Registry
Call startSection("win_reg_uninstall",124,timeUntil)
Set rego = GetObject("WinMgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
diff --git a/inventory/win_wmi_updates b/inventory/win_wmi_updates
new file mode 100644
index 0000000..3a415b5
--- /dev/null
+++ b/inventory/win_wmi_updates
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2013 mk(a)mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+
+# Example output
+#<<<win_wmi_updates:sep(44):cached(1494868004,3600)>>>
+#Node,Description,HotFixID,InstalledOn^M
+#S050MWSIZ001,Update,KB2849697,5/10/2017^M
+#S050MWSIZ001,Update,KB2849697,5/10/2017^M
+#S050MWSIZ001,Update,KB2849696,5/10/2017^M
+#S050MWSIZ001,Update,KB2849696,5/10/2017^M
+#S050MWSIZ001,Update,KB2841134,5/10/2017^M
+# Microsoft Office Professional Plus 2010|Microsoft Corporation|14.0.7015.1000
+
+
+def inv_win_wmi_updates(info):
+ paclist = inv_tree("software.packages:")
+ for line in info:
+ if len(line) <> 4:
+ continue
+
+ _, description, knowledge_base, install_date = line
+ date_number = None
+ if re.match(".*20.", install_date):
+ date_number = int(time.mktime(time.strptime(install_date, "%m/%d/%Y")))
+ paclist.append({
+ "name" : "Windows Update " + knowledge_base,
+ "version" : knowledge_base,
+ "vendor" : "Micorosoft " + description,
+ "install_date" : date_number,
+ "package_type" : "wmi",
+ })
+
+
+inv_info['win_wmi_updates'] = {
+ "inv_function": inv_win_wmi_updates,
+}
Module: check_mk
Branch: master
Commit: dd8d0ba81f81d32f7981d1a6b1e991a71f4fe3d0
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=dd8d0ba81f81d3…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Tue Jan 30 08:09:31 2018 +0100
5662 Tactical overview: Can now be configured to not show stale hosts/services
There is a new permission <i>See stale objects in tactical overview snapin</i> which
can be used to hide the stale hosts and services column from the tactical overview
snapin. This permission is enabled by default for all roles to stick with the current
default behaviour.
Change-Id: I9db89529f80f7877734d2b1821ab84b9aaed85fd
---
.werks/5662 | 13 +++++++++++++
web/htdocs/default_permissions.py | 5 +++++
web/plugins/sidebar/shipped.py | 6 ++++--
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/.werks/5662 b/.werks/5662
new file mode 100644
index 0000000..374770a
--- /dev/null
+++ b/.werks/5662
@@ -0,0 +1,13 @@
+Title: Tactical overview: Can now be configured to not show stale hosts/services
+Level: 1
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.5.0i3
+Date: 1517296086
+Class: feature
+
+There is a new permission <i>See stale objects in tactical overview snapin</i> which
+can be used to hide the stale hosts and services column from the tactical overview
+snapin. This permission is enabled by default for all roles to keep the current
+default behaviour.
diff --git a/web/htdocs/default_permissions.py b/web/htdocs/default_permissions.py
index 6cfac31..0cdb5fe 100644
--- a/web/htdocs/default_permissions.py
+++ b/web/htdocs/default_permissions.py
@@ -165,6 +165,11 @@ def load_plugins(force):
"and the configured <a href=\"wato.py?mode=edit_configvar&varname=failed_notification_horizon\">Failed notification horizon</a>."),
[ "admin" ])
+ config.declare_permission("general.see_stales_in_tactical_overview",
+ _("See stale objects in tactical overview snapin"),
+ _("Show the column for stale host and service checks in the tactical overview snapin."),
+ [ "guest", "user", "admin" ])
+
loaded_with_language = current_language
diff --git a/web/plugins/sidebar/shipped.py b/web/plugins/sidebar/shipped.py
index dff3f4c..20cc2e2 100644
--- a/web/plugins/sidebar/shipped.py
+++ b/web/plugins/sidebar/shipped.py
@@ -755,6 +755,8 @@ def render_tactical_overview(extra_filter_headers="", extra_url_variables=None):
html.open_table(class_=["content_center", "tacticaloverview"], cellspacing=2, cellpadding=0, border=0)
+ show_stales = config.user.may("general.see_stales_in_tactical_overview")
+
for row in rows:
if row["what"] == "event":
amount, problems, unhandled_problems = row["data"]
@@ -770,7 +772,7 @@ def render_tactical_overview(extra_filter_headers="", extra_url_variables=None):
html.th(row["title"])
html.th(_("Problems"))
html.th(_("Unhandled"))
- if td_class == 'col4':
+ if show_stales and td_class == 'col4':
html.th(_("Stale"))
html.close_tr()
@@ -786,7 +788,7 @@ def render_tactical_overview(extra_filter_headers="", extra_url_variables=None):
link(str(value), url)
html.close_td()
- if td_class == 'col4':
+ if show_stales and td_class == 'col4':
if row["views"]["stale"]:
url = html.makeuri_contextless(row["views"]["stale"] + extra_url_variables, filename="view.py")
html.open_td(class_=[td_class, "states prob" if stales != 0 else None])
Module: check_mk
Branch: master
Commit: 9652e803814a7d8387592e788ddb59360deaa1d2
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=9652e803814a7d…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Mon Jan 29 17:32:03 2018 +0100
5661 Publish views (and dashboard): Only own contact groups are selectable for users
Views and also dashboards can be published to members of contact groups. Earlier versions
allowed even normal users to select any configured contact group to publish these things to.
We have changed this now for normal monitoring users. They can now only select contact groups
which they are a member of. If you need the old behaviour back, you can enable the permission
"Publish views to foreign contact groups" for them.
Administators have this permission by default and can still publish views/dashboards to the
members of any contact group.
Change-Id: I3fc589285dd9452fc4b16b2d127d9a8d58308943
---
.werks/5661 | 18 ++++++++++++++++++
web/htdocs/default_permissions.py | 5 +++++
web/htdocs/userdb.py | 10 ++++++----
web/htdocs/visuals.py | 9 +++++++--
4 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/.werks/5661 b/.werks/5661
new file mode 100644
index 0000000..82bbf1b
--- /dev/null
+++ b/.werks/5661
@@ -0,0 +1,18 @@
+Title: Publish views (and dashboard): Only own contact groups are selectable for users
+Level: 1
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.5.0i3
+Date: 1517243324
+Class: feature
+
+Views and also dashboards can be published to members of contact groups. Earlier versions
+allowed even normal users to select any configured contact group to publish these things to.
+
+We have changed this now for normal monitoring users. They can now only select contact groups
+which they are a member of. If you need the old behaviour back, you can enable the permission
+"Publish views to foreign contact groups" for them.
+
+Administators have this permission by default and can still publish views/dashboards to the
+members of any contact group.
diff --git a/web/htdocs/default_permissions.py b/web/htdocs/default_permissions.py
index 4152535..6cfac31 100644
--- a/web/htdocs/default_permissions.py
+++ b/web/htdocs/default_permissions.py
@@ -180,6 +180,11 @@ def declare_visual_permissions(what, what_plural):
_("Make %s visible and usable for other users.") % what_plural,
[ "admin", "user" ])
+ config.declare_permission("general.publish_" + what + "_to_foreign_groups",
+ _("Publish %s to foreign contact groups") % what_plural,
+ _("Make %s visible and usable for users of contact groups the publishing user is not a member of.") % what_plural,
+ [ "admin" ])
+
config.declare_permission("general.see_user_" + what,
_("See user %s") % what_plural,
_("Is needed for seeing %s that other users have created.") % what_plural,
diff --git a/web/htdocs/userdb.py b/web/htdocs/userdb.py
index 49ed4c3..4b122e9 100644
--- a/web/htdocs/userdb.py
+++ b/web/htdocs/userdb.py
@@ -1030,15 +1030,17 @@ def load_group_information():
class GroupChoice(DualListChoice):
- def __init__(self, what, **kwargs):
+ def __init__(self, what, with_foreign_groups=True, **kwargs):
DualListChoice.__init__(self, **kwargs)
self.what = what
- self._choices = lambda: self.load_groups()
+ self._choices = lambda: self.load_groups(with_foreign_groups)
- def load_groups(self):
+
+ def load_groups(self, with_foreign_groups):
all_groups = load_group_information()
this_group = all_groups.get(self.what, {})
- return [ (k, t['alias'] and t['alias'] or k) for (k, t) in this_group.items() ]
+ return [ (k, t['alias'] and t['alias'] or k) for (k, t) in this_group.items()
+ if with_foreign_groups or k in config.user.contact_groups() ]
#.
diff --git a/web/htdocs/visuals.py b/web/htdocs/visuals.py
index 3fbf38e..af877f7 100644
--- a/web/htdocs/visuals.py
+++ b/web/htdocs/visuals.py
@@ -730,7 +730,11 @@ def page_edit_visual(what, all_visuals, custom_field_handler = None,
)),
]
if config.user.may("general.publish_" + what):
- visibility_elements.append(('public', PublishTo(type_title=visual_type["title"])))
+ with_foreign_groups = config.user.may("general.publish_" + what + "_to_foreign_groups")
+ visibility_elements.append(('public', PublishTo(
+ type_title=visual_type["title"],
+ with_foreign_groups=with_foreign_groups,
+ )))
vs_general = Dictionary(
title = _("General Properties"),
@@ -880,12 +884,13 @@ def page_edit_visual(what, all_visuals, custom_field_handler = None,
class PublishTo(CascadingDropdown):
- def __init__(self, type_title=None, **kwargs):
+ def __init__(self, type_title=None, with_foreign_groups=True, **kwargs):
super(PublishTo, self).__init__(
choices = [
(True, _("Publish to all users")),
("contact_groups", _("Publish to members of contact groups"), userdb.GroupChoice(
"contact",
+ with_foreign_groups=with_foreign_groups,
title = _("Publish to members of contact groups"),
rows = 5,
size = 40,
Module: check_mk
Branch: master
Commit: 09058ce0b8648e4c11145e71ac6f2f5fcac066b4
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=09058ce0b8648e…
Author: Simon Betz <si(a)mathias-kettner.de>
Date: Thu Jan 25 12:20:06 2018 +0100
Updated werk 5605; Moved rule option 'Do status data inventory' to 'Do hardware/software inventory' rule
Change-Id: Iac257e189011318478a523c034c966b727f797cd
---
.werks/5605 | 9 +++++----
cmk_base/checks.py | 11 ++++++++++-
cmk_base/inventory.py | 32 ++++++++++++++++++--------------
web/plugins/wato/inventory.py | 25 ++++++++++++++-----------
4 files changed, 47 insertions(+), 30 deletions(-)
diff --git a/.werks/5605 b/.werks/5605
index 4138368..32d2204 100644
--- a/.werks/5605
+++ b/.werks/5605
@@ -31,10 +31,11 @@ Later in the web GUI both tree objects are merged and visible below 'Inventory'.
Inventory history is only calculated for the inventory data, not for the
status data.
-In order to use this feature you have to enable the rule
-'Do status data inventory' for a host. When it's enabled Check_MK does a
-HW/Sw inventory for this host after every check cycle if and only if there's
-a inventory plugin which fills up status data tree.
+If the rule 'Do hardware/software inventory' is enabled for a host then
+doing status data inventory is also enabled. In this case Check_MK does a
+HW/SW inventory for this host after every check cycle if and only if there's a
+inventory plugin which fills up status data tree.
+Within above ruleset 'do status data inventory' can be disabled.
Notes for inventory plugin development:
Previously an inventory plugin used the functions inv_tree_list and inv_tree
diff --git a/cmk_base/checks.py b/cmk_base/checks.py
index 13321b9..e0c9104 100644
--- a/cmk_base/checks.py
+++ b/cmk_base/checks.py
@@ -613,5 +613,14 @@ def get_management_board_precedence(check_plugin_name):
else:
return mgmt_board
+
def do_status_data_inventory_for(hostname):
- return rulesets.in_binary_hostlist(hostname, config.status_data_inventory)
+ rules = config.active_checks.get('cmk_inv')
+ # 'host_extra_conf' is already cached thus we can
+ # use it after every check cycle.
+ params = rulesets.host_extra_conf(hostname, rules)
+ if params:
+ # Means: Enabled "Do hardware/software inventory",
+ # => params is at least [{}]
+ return params[0].get('status_data_inventory', True)
+ return False
diff --git a/cmk_base/inventory.py b/cmk_base/inventory.py
index 9b6bd24..26263ab 100644
--- a/cmk_base/inventory.py
+++ b/cmk_base/inventory.py
@@ -84,20 +84,18 @@ def do_inv(hostnames):
errors = []
for hostname in hostnames:
try:
- console.verbose("Doing HW/SW-Inventory for %s..." % hostname)
-
if config.is_cluster(hostname):
ipaddress = None
else:
ipaddress = ip_lookup.lookup_ip_address(hostname)
do_inv_for(hostname, ipaddress)
- console.verbose("..OK\n")
+ console.verbose(" OK\n")
except Exception, e:
if cmk.debug.enabled():
raise
- console.verbose("Failed: %s\n" % e)
+ console.verbose(" Failed: %s\n" % e)
errors.append("Failed to inventorize %s: %s" % (hostname, e))
finally:
for data_source, exceptions in data_sources.get_data_source_errors_of_host(hostname, ipaddress).items():
@@ -173,6 +171,8 @@ def do_inv_check(options, hostname):
def do_inv_for(hostname, ipaddress):
+ console.verbose("Doing HW/SW inventory for %s;" % hostname)
+
_initialize_inventory_tree()
inventory_tree = g_inv_tree
status_data_tree = StructuredDataTree()
@@ -185,15 +185,17 @@ def do_inv_for(hostname, ipaddress):
node["is_cluster"] = False
_do_inv_for_realhost(hostname, ipaddress, inventory_tree, status_data_tree)
- if not status_data_tree.is_empty():
- status_data_tree.normalize_nodes()
- _save_status_data_tree(hostname, status_data_tree)
-
inventory_tree.normalize_nodes()
old_timestamp = _save_inventory_tree(hostname, inventory_tree)
- console.verbose("..%s%s%d%s entries" %
+ console.verbose(" %s%s%d%s entries;" %
(tty.bold, tty.yellow, inventory_tree.count_entries(), tty.normal))
+ if not status_data_tree.is_empty():
+ status_data_tree.normalize_nodes()
+ _save_status_data_tree(hostname, status_data_tree)
+ console.verbose(" Status data inventory: %s%s%d%s entries;" %
+ (tty.bold, tty.yellow, status_data_tree.count_entries(), tty.normal))
+
_run_inventory_export_hooks(hostname, inventory_tree)
return old_timestamp, inventory_tree
@@ -219,6 +221,7 @@ def _do_inv_for_realhost(hostname, ipaddress, inventory_tree, status_data_tree):
multi_host_sections = sources.get_host_sections(hostname, ipaddress)
+ console.verbose(" Execute inventory plugins;")
import cmk_base.inventory_plugins
for section_name, plugin in cmk_base.inventory_plugins.inv_info.items():
section_content = multi_host_sections.get_section_content(hostname, ipaddress,
@@ -233,7 +236,7 @@ def _do_inv_for_realhost(hostname, ipaddress, inventory_tree, status_data_tree):
# Note: this also excludes existing sections without info..
continue
- console.verbose(tty.green + tty.bold + section_name + " " + tty.normal)
+ console.verbose(" %s%s%s%s" % (tty.green, tty.bold, section_name, tty.normal))
# Inventory functions can optionally have a second argument: parameters.
# These are configured via rule sets (much like check parameters).
@@ -254,6 +257,7 @@ def _do_inv_for_realhost(hostname, ipaddress, inventory_tree, status_data_tree):
else:
args = [section_content]
inv_function(*args, **kwargs)
+ console.verbose(";")
def _gather_snmp_check_plugin_names_inventory(hostname, ipaddress, on_error, do_snmp_scan):
@@ -319,12 +323,12 @@ def _save_inventory_tree(hostname, inventory_tree):
if inventory_tree:
old_tree = StructuredDataTree().load_from(filepath)
if old_tree.is_equal(inventory_tree):
- console.verbose("..unchanged")
+ console.verbose(" unchanged;")
else:
if old_tree.is_empty():
- console.verbose("..new")
+ console.verbose(" new;")
else:
- console.verbose("..changed")
+ console.verbose(" changed;")
old_time = os.stat(filepath).st_mtime
arcdir = "%s/%s" % (inventory_archive_dir, hostname)
if not os.path.exists(arcdir):
@@ -361,7 +365,7 @@ def _run_inventory_export_hooks(hostname, inventory_tree):
for hookname, ruleset in config.inv_exports.items():
entries = rulesets.host_extra_conf(hostname, ruleset)
if entries:
- console.verbose(", running %s%s%s%s..." % (tty.blue, tty.bold, hookname, tty.normal))
+ console.verbose(" running %s%s%s%s;" % (tty.blue, tty.bold, hookname, tty.normal))
params = entries[0]
try:
cmk_base.inventory_plugins.inv_export[hookname]["export_function"](hostname, params, inventory_tree.get_raw_tree())
diff --git a/web/plugins/wato/inventory.py b/web/plugins/wato/inventory.py
index 52aac82..698e9eb 100644
--- a/web/plugins/wato/inventory.py
+++ b/web/plugins/wato/inventory.py
@@ -60,6 +60,20 @@ register_rule(group,
"off - so you will get no notifications in that case."),
default_value = 1,
)),
+ ("status_data_inventory", DropdownChoice(
+ title=_("Status data inventory"),
+ help=_("All hosts configured via this ruleset will do a hardware and "
+ "software inventory after every check cycle if there's at least "
+ "one inventory plugin which processes status data. "
+ "<b>Note:</b> in order to get any useful "
+ "result for agent based hosts make sure that you have installed "
+ "the agent plugin <tt>mk_inventory</tt> on these hosts."),
+ choices=[
+ (True, _("Do status data inventory")),
+ (False, _("Do not status data inventory")),
+ ],
+ default_value=True,
+ )),
]
),
title = _("Do hardware/software Inventory"),
@@ -149,14 +163,3 @@ register_rule(group,
),
match = "dict",
)
-
-register_rule(group,
- "status_data_inventory",
- title=_("Do status data inventory"),
- help=_("All hosts configured via this ruleset will do a hardware and "
- "software inventory after every check cycle if there's at least "
- "one inventory plugin which processes status data. "
- "<b>Note:</b> in order to get any useful "
- "result for agent based hosts make sure that you have installed "
- "the agent plugin <tt>mk_inventory</tt> on these hosts."),
-)