Module: check_mk
Branch: master
Commit: c14f8e9ec97a4a7f8c2df0e2c5642c281894193e
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=c14f8e9ec97a4a…
Author: Tom Baerwinkel <tb(a)mathias-kettner.de>
Date: Fri Feb 8 11:58:41 2019 +0100
notify.py: align log levels with cmk/utils/log.py
This will make it easier to switch to the logging
module later on.
Change-Id: I473bf64e33b0a575a7e0c37493eb70d81de34c06
---
cmk/gui/plugins/wato/globals_notification.py | 19 ++++++++++++++++---
cmk_base/default_config/notify.py | 8 ++++----
cmk_base/notify.py | 19 +++++++++++--------
3 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/cmk/gui/plugins/wato/globals_notification.py b/cmk/gui/plugins/wato/globals_notification.py
index 338f2a3..568e931 100644
--- a/cmk/gui/plugins/wato/globals_notification.py
+++ b/cmk/gui/plugins/wato/globals_notification.py
@@ -198,9 +198,11 @@ class ConfigVariableNotificationLogging(ConfigVariable):
def valuespec(self):
return Transform(
DropdownChoice(
- choices=[(1, _("Normal logging")), (2,
- _("Full dump of all variables and command"))],),
- forth=lambda x: x == 0 and 1 or x, # transform deprecated value 0 (no logging) to 1
+ choices=[
+ (20, _("Normal logging")),
+ (10, _("Full dump of all variables and command")),
+ ],),
+ forth=self._transform_log_level,
title=_("Notification log level"),
help=_("You can configure the notification mechanism to log more details about "
"the notifications into the notification log. This information are logged "
@@ -208,6 +210,17 @@ class ConfigVariableNotificationLogging(ConfigVariable):
site_neutral_path(cmk.utils.paths.log_dir + "/notify.log"),
)
+ @staticmethod
+ def _transform_log_level(level):
+ # The former values 1 and 2 are mapped to the values 20 (default) and 10 (debug)
+ # which agree with the values used in cmk/utils/log.py.
+ # The decprecated value 0 is transformed to the default logging value.
+ if level in [0, 1]:
+ return 20
+ elif level == 2:
+ return 10
+ return level
+
@config_variable_registry.register
class ConfigVariableServiceLevels(ConfigVariable):
diff --git a/cmk_base/default_config/notify.py b/cmk_base/default_config/notify.py
index 205be0d..8f75cb2 100644
--- a/cmk_base/default_config/notify.py
+++ b/cmk_base/default_config/notify.py
@@ -27,10 +27,10 @@
import cmk as _cmk
# Log level of notifications
-# 0 -> deprecated (transformed to 1)
-# 1 -> normal logging
-# 2 -> full dump of all variables and command
-notification_logging = 1
+# 0, 1, 2 -> deprecated (transformed to 20, 20, and 10)
+# 20 -> normal logging
+# 10 -> full dump of all variables and command
+notification_logging = 20
notification_backlog = 10 # keep the last 10 notification contexts for reference
# Settings for new rule based notifications
diff --git a/cmk_base/notify.py b/cmk_base/notify.py
index 8c38be3..866fba7 100755
--- a/cmk_base/notify.py
+++ b/cmk_base/notify.py
@@ -246,9 +246,13 @@ def convert_legacy_configuration():
else:
config.notification_spooling = "remote"
- # transform deprecated value 0 to 1
- if config.notification_logging == 0:
- config.notification_logging = 1
+ # The former values 1 and 2 are mapped to the values 20 (default) and 10 (debug)
+ # which agree with the values used in cmk/utils/log.py.
+ # The decprecated value 0 is transformed to the default logging value.
+ if config.notification_logging in [0, 1]:
+ config.notification_logging = 20
+ elif config.notification_logging == 2:
+ config.notification_logging = 10
# This function processes one raw notification and decides wether it
@@ -268,12 +272,11 @@ def notify_notify(raw_context, analyse=False):
# Add some further variable for the conveniance of the plugins
- if config.notification_logging >= 2:
- notify_log(events.render_context_dump(raw_context))
+ notify_log_debug(events.render_context_dump(raw_context))
_complete_raw_context_with_notification_vars(raw_context)
events.complete_raw_context(
- raw_context, with_dump=config.notification_logging >= 2, log_func=notify_log)
+ raw_context, with_dump=config.notification_logging <= 10, log_func=notify_log)
# Spool notification to remote host, if this is enabled
if config.notification_spooling in ("remote", "both"):
@@ -1908,12 +1911,12 @@ def dead_nagios_variable(value):
def notify_log(message):
- if config.notification_logging >= 1:
+ if config.notification_logging <= 20:
events.event_log(notification_log, message)
def notify_log_debug(message):
- if config.notification_logging >= 2:
+ if config.notification_logging <= 10:
events.event_log(notification_log, message)
Module: check_mk
Branch: master
Commit: 5850073038dc3ded43c6a81c5e3aa9fb96516afe
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=5850073038dc3d…
Author: Tom Baerwinkel <tb(a)mathias-kettner.de>
Date: Fri Feb 8 14:31:28 2019 +0100
7059 Add an option to reduce the logging in the notify.log
By default two lines are added for every notification rule in the
notify.log. They contain a short description of the rule and
information why the rule does or does not match. In setups with
a large number of notification rules this may result in up to
hundreds of lines in the notify.log for every incoming raw
notification. To optionally reduce the amount of logging this
werk introduces a new log level that only adds lines for matching
rules. The new option can be selected in the Global Settings under
"Notification log level". Be aware that with this option the
notify.log does not conain information about rules which do not
match which makes it much harder to analyze why a certain rule
did not match retrospectively.
Change-Id: Id8c93e9aadb35c0f7e3c481de1209c344755a0b6
---
.werks/7059 | 21 +++++++++++++++++++++
cmk/gui/plugins/wato/globals_notification.py | 3 ++-
cmk_base/default_config/notify.py | 5 +++--
cmk_base/notify.py | 13 ++++++++++---
4 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/.werks/7059 b/.werks/7059
new file mode 100644
index 0000000..6f287d8
--- /dev/null
+++ b/.werks/7059
@@ -0,0 +1,21 @@
+Title: Add an option to reduce the logging in the notify.log
+Level: 1
+Component: notifications
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1550494196
+Class: feature
+
+By default two lines are added for every notification rule in the
+notify.log. They contain a short description of the rule and
+information why the rule does or does not match. In setups with
+a large number of notification rules this may result in up to
+hundreds of lines in the notify.log for every incoming raw
+notification. To optionally reduce the amount of logging this
+werk introduces a new log level that only adds lines for matching
+rules. The new option can be selected in the Global Settings under
+"Notification log level". Be aware that with this option the
+notify.log does not conain information about rules which do not
+match which makes it much harder to analyze why a certain rule
+did not match retrospectively.
diff --git a/cmk/gui/plugins/wato/globals_notification.py b/cmk/gui/plugins/wato/globals_notification.py
index 568e931..1b53317 100644
--- a/cmk/gui/plugins/wato/globals_notification.py
+++ b/cmk/gui/plugins/wato/globals_notification.py
@@ -199,7 +199,8 @@ class ConfigVariableNotificationLogging(ConfigVariable):
return Transform(
DropdownChoice(
choices=[
- (20, _("Normal logging")),
+ (20, _("Minimal logging")),
+ (15, _("Normal logging")),
(10, _("Full dump of all variables and command")),
],),
forth=self._transform_log_level,
diff --git a/cmk_base/default_config/notify.py b/cmk_base/default_config/notify.py
index 8f75cb2..5bc3161 100644
--- a/cmk_base/default_config/notify.py
+++ b/cmk_base/default_config/notify.py
@@ -28,9 +28,10 @@ import cmk as _cmk
# Log level of notifications
# 0, 1, 2 -> deprecated (transformed to 20, 20, and 10)
-# 20 -> normal logging
+# 20 -> minimal logging
+# 15 -> normal logging
# 10 -> full dump of all variables and command
-notification_logging = 20
+notification_logging = 15
notification_backlog = 10 # keep the last 10 notification contexts for reference
# Settings for new rule based notifications
diff --git a/cmk_base/notify.py b/cmk_base/notify.py
index 866fba7..f669089 100755
--- a/cmk_base/notify.py
+++ b/cmk_base/notify.py
@@ -428,15 +428,17 @@ def notify_rulebased(raw_context, analyse=False):
for rule in config.notification_rules + user_notification_rules():
if "contact" in rule:
- notify_log("User %s's rule '%s'..." % (rule["contact"], rule["description"]))
+ contact_info = "User %s's rule '%s'..." % (rule["contact"], rule["description"])
else:
- notify_log("Global rule '%s'..." % rule["description"])
+ contact_info = "Global rule '%s'..." % rule["description"]
why_not = rbn_match_rule(rule, raw_context) # also checks disabling
if why_not:
- notify_log(" -> does not match: %s" % why_not)
+ notify_log_verbose(contact_info)
+ notify_log_verbose(" -> does not match: %s" % why_not)
rule_info.append(("miss", rule, why_not))
else:
+ notify_log(contact_info)
notify_log(" -> matches!")
num_rule_matches += 1
contacts = rbn_rule_contacts(rule, raw_context)
@@ -1915,6 +1917,11 @@ def notify_log(message):
events.event_log(notification_log, message)
+def notify_log_verbose(message):
+ if config.notification_logging <= 15:
+ events.event_log(notification_log, message)
+
+
def notify_log_debug(message):
if config.notification_logging <= 10:
events.event_log(notification_log, message)
Module: check_mk
Branch: master
Commit: 0b3ea32976e604bd2e45455b5d07acc0731ae7b5
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0b3ea32976e604…
Author: Moritz Kiemer <mo(a)mathias-kettner.de>
Date: Fri Feb 15 12:53:34 2019 +0100
7145 jolokia_info: Also discover if server is not responding
Every instance that is contacted has been explicitly configured by the user.
We can assume they want to monitor it, even if an error occurs at the time
of discovery.
Change-Id: I36b557bfe15ac1c13065652a6837f540091d418f
---
.werks/7145 | 13 ++++++
agents/plugins/mk_jolokia.py | 8 ++--
checks/jolokia_info | 37 ++++++++--------
.../datasets/jolokia_info_regression.py | 50 ++++++++++++++++++++++
4 files changed, 85 insertions(+), 23 deletions(-)
diff --git a/.werks/7145 b/.werks/7145
new file mode 100644
index 0000000..aee988e
--- /dev/null
+++ b/.werks/7145
@@ -0,0 +1,13 @@
+Title: jolokia_info: Also discover if server is not responding
+Level: 1
+Component: checks
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1550231470
+Class: feature
+
+Every instance that is contacted has been explicitly configured by the user.
+We can assume they want to monitor it, even if an error occurs at the time
+of discovery.
+
diff --git a/agents/plugins/mk_jolokia.py b/agents/plugins/mk_jolokia.py
index a8dc71b..df8ca52 100755
--- a/agents/plugins/mk_jolokia.py
+++ b/agents/plugins/mk_jolokia.py
@@ -37,8 +37,8 @@ try:
except ImportError as import_error:
sys.stdout.write(
"<<<jolokia_info>>>\n"
- "Error: mk_jolokia requires either the json or simplejson library.\n"
- "Please either use a Python version that contains the json library or install the"
+ "Error: mk_jolokia requires either the json or simplejson library."
+ " Please either use a Python version that contains the json library or install the"
" simplejson library on the monitored system.")
sys.exit(1)
@@ -47,8 +47,8 @@ try:
from requests.auth import HTTPDigestAuth
except ImportError as import_error:
sys.stdout.write("<<<jolokia_info>>>\n"
- "Error: mk_jolokia requires the requests library.\n"
- "Please install it on the monitored system.")
+ "Error: mk_jolokia requires the requests library."
+ " Please install it on the monitored system.")
sys.exit(1)
VERBOSE = '--verbose' in sys.argv
diff --git a/checks/jolokia_info b/checks/jolokia_info
index cfc37e5..93a696a 100644
--- a/checks/jolokia_info
+++ b/checks/jolokia_info
@@ -25,34 +25,33 @@
# Boston, MA 02110-1301 USA.
-def inventory_jolokia_info(info):
- return [(line[0], None) for line in info if line[1] != 'ERROR']
+def parse_jolokia_info(info):
+ parsed = {}
+ for line in info:
+ parsed.setdefault(line[0], []).append(line[1:])
+ return parsed
-def check_jolokia_info(item, _no_params, info):
+@get_parsed_item_data
+def check_jolokia_info(item, _no_params, data):
+ line = data[0]
# Inform user of non-working agent plugin, eg. missing json library
- if info[0][0] == "Error:":
- return 3, " ".join(info[0])
-
- for line in info:
- if line[0] == item:
- if line[1] == 'ERROR' or len(line) < 4:
- return (2, "Jolokia not running")
+ if item == "Error:":
+ return 3, ' '.join(line)
- if len(line) > 4:
- product = line[1]
- jolokia_version = line[-1]
- version = " ".join(line[2:-1])
- else:
- product, version, jolokia_version = line[1:]
- return (0, "%s %s (Jolokia version %s)" % (product.title(), version, jolokia_version))
+ if line[0] == 'ERROR' or len(line) < 3:
+ return 2, ' '.join(line) or "Unknown error in plugin"
- return (3, "No data from agent, server might be down")
+ product = line[0]
+ jolokia_version = line[-1]
+ version = " ".join(line[1:-1])
+ return 0, "%s %s (Jolokia version %s)" % (product.title(), version, jolokia_version)
check_info["jolokia_info"] = {
+ "parse_function": parse_jolokia_info,
"service_description": "JVM %s",
"check_function": check_jolokia_info,
- "inventory_function": inventory_jolokia_info,
+ "inventory_function": discover(),
}
diff --git a/tests/unit/checks/generictests/datasets/jolokia_info_regression.py b/tests/unit/checks/generictests/datasets/jolokia_info_regression.py
new file mode 100644
index 0000000..613e375
--- /dev/null
+++ b/tests/unit/checks/generictests/datasets/jolokia_info_regression.py
@@ -0,0 +1,50 @@
+
+
+checkname = 'jolokia_info'
+
+
+info = [['Error:',
+ 'mk_jolokia',
+ 'requires',
+ 'either',
+ 'the',
+ 'json',
+ 'or',
+ 'simplejson',
+ 'library.',
+ 'Please',
+ 'either',
+ 'use',
+ 'a',
+ 'Python',
+ 'version',
+ 'that',
+ 'contains',
+ 'the',
+ 'json',
+ 'library',
+ 'or',
+ 'install',
+ 'the',
+ 'simplejson',
+ 'library',
+ 'on',
+ 'the',
+ 'monitored',
+ 'system.'],
+ ['INSTANCE1', 'ERROR', 'HTTP404 No response from server or whatever'],
+ ['INSTANCE2', 'tomcat', '3.141592', '42.23']]
+
+
+discovery = {'': [('Error:', {}), ('INSTANCE1', {}), ('INSTANCE2', {})]}
+
+
+checks = {'': [('Error:',
+ {},
+ [(3,
+ 'mk_jolokia requires either the json or simplejson library. Please either use a Python version that contains the json library or install the simplejson library on the monitored system.',
+ [])]),
+ ('INSTANCE1',
+ {},
+ [(2, 'ERROR HTTP404 No response from server or whatever', [])]),
+ ('INSTANCE2', {}, [(0, 'Tomcat 3.141592 (Jolokia version 42.23)', [])])]}
Module: check_mk
Branch: master
Commit: 46962449a488d804da54289487a37884617d16cd
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=46962449a488d8…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Feb 15 16:10:41 2019 +0100
7087 Extension packages can now provide individual localizations
Extension packages (MKPs) can now ship their own localization files in addition
to the standard localization file. With this change it is possible to split
different localization parts into separate files.
The GUI now recognizes the following localization file paths:
C+:
share/check_mk/locale/[LANG]/LC_MESSAGES/multisite.mo - Builtin, shipped with Check_MK.
local/share/check_mk/locale/[LANG]/LC_MESSAGES/multisite.mo - Site specific override, extension of builtin localization
local/share/check_mk/locale/packages/[PKG_NAME]/[LANG]/LC_MESSAGES/multisite.mo - Extension localization
C-:
The GUI searches these localization files from bottom to top when it searches for
a text to be localized.
Change-Id: I44f1915f83525bcaf41a711de107b4d422c42abd
---
.werks/7087 | 23 +++++++++++++++++++++++
cmk/gui/i18n.py | 30 ++++++++++++++++++++++++++----
tests/unit/cmk/gui/test_i18n.py | 25 +++++++++++++++++++------
3 files changed, 68 insertions(+), 10 deletions(-)
diff --git a/.werks/7087 b/.werks/7087
new file mode 100644
index 0000000..e109eda
--- /dev/null
+++ b/.werks/7087
@@ -0,0 +1,23 @@
+Title: Extension packages can now provide individual localizations
+Level: 1
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1550243073
+Class: feature
+
+Extension packages (MKPs) can now ship their own localization files in addition
+to the standard localization file. With this change it is possible to split
+different localization parts into separate files.
+
+The GUI now recognizes the following localization file paths:
+
+C+:
+share/check_mk/locale/[LANG]/LC_MESSAGES/multisite.mo - Builtin, shipped with Check_MK.
+local/share/check_mk/locale/[LANG]/LC_MESSAGES/multisite.mo - Site specific override, extension of builtin localization
+local/share/check_mk/locale/packages/[PKG_NAME]/[LANG]/LC_MESSAGES/multisite.mo - Extension localization
+C-:
+
+The GUI searches these localization files from bottom to top when it searches for
+a text to be localized.
diff --git a/cmk/gui/i18n.py b/cmk/gui/i18n.py
index 5ac4a2d..35392f4 100644
--- a/cmk/gui/i18n.py
+++ b/cmk/gui/i18n.py
@@ -70,16 +70,39 @@ def get_current_language():
def _get_language_dirs():
# type: () -> List[str]
+ return _get_base_language_dirs() + _get_package_language_dirs()
+
+
+def _get_base_language_dirs():
+ # type: () -> List[str]
return [cmk.utils.paths.locale_dir, cmk.utils.paths.local_locale_dir]
+def _get_package_language_dirs():
+ # type: () -> List[str]
+ """Return a list of extension package specific localization directories
+
+ It's possible for extension packages to provide custom localization files
+ which are meant for localizing extension specific texts. These localizations
+ are then used in addition to the builtin and local localization files.
+ """
+ package_locale_dir = cmk.utils.paths.local_locale_dir + "/packages"
+ if not os.path.exists(package_locale_dir):
+ return []
+
+ dirs = []
+ for package_name in os.listdir(package_locale_dir):
+ dirs.append(package_locale_dir + "/" + package_name)
+ return dirs
+
+
def get_language_alias(lang):
# type: (Optional[str]) -> Text
if lang is None:
return _("English")
alias = lang
- for lang_dir in _get_language_dirs():
+ for lang_dir in _get_base_language_dirs():
try:
alias = open('%s/%s/alias' % (lang_dir, lang), 'r').read().strip()
except (OSError, IOError):
@@ -98,7 +121,7 @@ def get_languages():
try:
languages.update([(val, _("%s") % get_language_alias(val))
for val in os.listdir(lang_dir)
- if not '.' in val and os.path.isdir(lang_dir + "/" + val)])
+ if val != "packages" and os.path.isdir(lang_dir + "/" + val)])
except OSError:
# Catch "OSError: [Errno 2] No such file or
# directory:" when directory not exists
@@ -138,8 +161,7 @@ def _init_language(lang):
for locale_base_dir in _get_language_dirs():
try:
translation = gettext_module.translation(
- "multisite", locale_base_dir, languages=[lang],
- codeset='UTF-8') # type: gettext_module.NullTranslations
+ "multisite", locale_base_dir, languages=[lang], codeset='UTF-8')
except IOError:
continue
diff --git a/tests/unit/cmk/gui/test_i18n.py b/tests/unit/cmk/gui/test_i18n.py
index 10bae17..ce5c9e6 100644
--- a/tests/unit/cmk/gui/test_i18n.py
+++ b/tests/unit/cmk/gui/test_i18n.py
@@ -27,11 +27,13 @@ def compile_builtin_po_files(locale_paths):
@pytest.fixture()
def local_translation():
- _add_local_translation("de", u"Äxtended German")
- _add_local_translation("xz", "Xz")
+ _add_local_translation("de", u"Äxtended German", texts={"bla": "blub"})
+ _add_local_translation("xz", "Xz", texts={"bla": "blub"})
+ # Add one package localization
+ _add_local_translation("packages/pkg_name/de", "pkg_name German", texts={"pkg1": "lala"})
-def _add_local_translation(lang, alias):
+def _add_local_translation(lang, alias, texts):
local_dir = Path(cmk.utils.paths.local_locale_dir) / lang / "LC_MESSAGES"
local_dir.mkdir(parents=True) # pylint: disable=no-member
po_file = local_dir / "multisite.po"
@@ -52,11 +54,14 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
-
-msgid "bla"
-msgstr "blub"
''')
+ for key, val in texts.items():
+ f.write(u"""
+msgid "%s"
+msgstr "%s"
+""" % (key, val))
+
subprocess.call(['msgfmt', str(po_file), '-o', str(mo_file)])
@@ -118,6 +123,14 @@ def test_init_language_with_local_modification_fallback(local_translation):
assert translated == "Alter"
+def test_init_language_with_package_localization(local_translation):
+ trans = i18n._init_language("de")
+
+ translated = trans.ugettext("pkg1")
+ assert isinstance(translated, unicode)
+ assert translated == "lala"
+
+
def test_get_language_alias():
assert isinstance(i18n.get_language_alias(None), unicode)
assert i18n.get_language_alias(None) == "English"
Module: check_mk
Branch: master
Commit: ce3d897b866d6b11879c1c090ebff07bc27c576b
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=ce3d897b866d6b…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Feb 15 14:52:14 2019 +0100
7086 Localizations now extend shipped localizations
Locally installed localization files (local/share/check_mk/locale) may
now extend the builtin localizations instead of overriding them.
In previous versions the local locale file had to contain all texts that
we ship with our standard localizations, for example the german localization
in case one wanted to extend / change a single text.
Now both, the builtin and local localization files are loaded. All texts
are searched in the local file and looked up in the builtin file as fallback
in case the text can not be found in the local file.
Change-Id: I7941ed5a489f83c53246157febb1f3a89f6356a6
---
.werks/7086 | 19 +++++++++++++++++++
cmk/gui/i18n.py | 39 +++++++++++++++++++++++----------------
tests/unit/cmk/gui/test_i18n.py | 36 +++++++++++++++---------------------
3 files changed, 57 insertions(+), 37 deletions(-)
diff --git a/.werks/7086 b/.werks/7086
new file mode 100644
index 0000000..6da4b90
--- /dev/null
+++ b/.werks/7086
@@ -0,0 +1,19 @@
+Title: Localizations now extend shipped localizations
+Level: 1
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1550238596
+Class: feature
+
+Locally installed localization files (local/share/check_mk/locale) may
+now extend the builtin localizations instead of overriding them.
+
+In previous versions the local locale file had to contain all texts that
+we ship with our standard localizations, for example the german localization
+in case one wanted to extend / change a single text.
+
+Now both, the builtin and local localization files are loaded. All texts
+are searched in the local file and looked up in the builtin file as fallback
+in case the text can not be found in the local file.
diff --git a/cmk/gui/i18n.py b/cmk/gui/i18n.py
index 48fbb87..5ac4a2d 100644
--- a/cmk/gui/i18n.py
+++ b/cmk/gui/i18n.py
@@ -130,22 +130,29 @@ def localize(lang):
def _init_language(lang):
# type: (str) -> Optional[gettext_module.NullTranslations]
- try:
- translation = gettext_module.translation(
- "multisite", _get_cmk_locale_path(lang), languages=[lang],
- codeset='UTF-8') # type: Optional[gettext_module.NullTranslations]
- except IOError:
- translation = None
-
- return translation
-
-
-def _get_cmk_locale_path(lang):
- # type: (str) -> str
- po_path = '/%s/LC_MESSAGES/multisite.mo' % lang
- if os.path.exists(cmk.utils.paths.local_locale_dir + po_path):
- return cmk.utils.paths.local_locale_dir
- return cmk.utils.paths.locale_dir
+ """Load all available "multisite" translation files. All are loaded first.
+ The builtin ones are used as "fallback" for the local files which means that
+ the texts in the local files have precedence.
+ """
+ translations = [] # type: List[gettext_module.NullTranslations]
+ for locale_base_dir in _get_language_dirs():
+ try:
+ translation = gettext_module.translation(
+ "multisite", locale_base_dir, languages=[lang],
+ codeset='UTF-8') # type: gettext_module.NullTranslations
+
+ except IOError:
+ continue
+
+ # Create a chain of fallback translations
+ if translations:
+ translation.add_fallback(translations[-1])
+ translations.append(translation)
+
+ if not translations:
+ return None
+
+ return translations[-1]
def initialize():
diff --git a/tests/unit/cmk/gui/test_i18n.py b/tests/unit/cmk/gui/test_i18n.py
index 8504cd6..10bae17 100644
--- a/tests/unit/cmk/gui/test_i18n.py
+++ b/tests/unit/cmk/gui/test_i18n.py
@@ -75,15 +75,6 @@ def test_underscore_localization():
assert i18n.get_current_language() is None
-def test_get_locale_path():
- assert i18n._get_cmk_locale_path("de") == "%s/enterprise/locale" % cmk_path()
- assert i18n._get_cmk_locale_path("xz") == "%s/enterprise/locale" % cmk_path()
-
-
-def test_get_locale_path_with_local_modification(local_translation):
- assert i18n._get_cmk_locale_path("de") == cmk.utils.paths.local_locale_dir
-
-
def test_init_language_not_existing():
assert i18n._init_language("xz") is None
@@ -110,18 +101,21 @@ def test_init_language_with_local_modification(local_translation):
assert translated == "blub"
-# Will be enabled soon
-#def test_init_language_with_local_modification_fallback(local_translation):
-# trans = i18n._init_language("de")
-# assert isinstance(trans, gettext.GNUTranslations)
-# assert trans.info()["language"] == "de"
-# assert trans.info()["project-id-version"] == "Locally modified Check_MK translation"
-#
-# # This string is localized in the standard file, not in the locally
-# # overridden file
-# translated = trans.ugettext("Age")
-# assert isinstance(translated, unicode)
-# assert translated == "Alter"
+def test_init_language_with_local_modification_fallback(local_translation):
+ trans = i18n._init_language("de")
+ assert isinstance(trans, gettext.GNUTranslations)
+ assert trans.info()["language"] == "de"
+ assert trans.info()["project-id-version"] == "Locally modified Check_MK translation"
+
+ translated = trans.ugettext("bla")
+ assert isinstance(translated, unicode)
+ assert translated == "blub"
+
+ # This string is localized in the standard file, not in the locally
+ # overridden file
+ translated = trans.ugettext("Age")
+ assert isinstance(translated, unicode)
+ assert translated == "Alter"
def test_get_language_alias():
Module: check_mk
Branch: master
Commit: 640884c9769981f2036f4174655433e43b4d87ae
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=640884c9769981…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Sun Feb 17 21:54:40 2019 +0100
Fix some chdir calls remaining in target dir
Some actions currently perform os.chdir() calls but were not
correctly returning to the source directory.
This issue has now been fixed by introducing a context manager
that cares about restoring the previous state.
CMK-1603
Change-Id: I3db60082e396932a8229f86e4675c77f6ec5fa77
---
omd/packages/omd/omdlib/main.py | 209 +++++++++++++++++++++-------------------
1 file changed, 109 insertions(+), 100 deletions(-)
Diff: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commitdiff;h=640884c976…
Module: check_mk
Branch: master
Commit: e78e200533bc011e2850effabf4e2a5fcffa4a2c
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=e78e200533bc01…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Mon Feb 18 09:30:01 2019 +0100
7089 Docker container: Simplified update procedure
The update procedure of the official Check_MK containers was a bit complicated
compared to the update procedure on other servers. The root cause for this was
that the update always required both, the old and the new versions, while the
containers are only allowed to have one version installed. This made it
necessary to create an intermediate container for the update.
The werk #7088 made it possible to perform an update without having access to
the old version. Once we have this functionality it is now possible to replace
one container with a another container. In case the version has changed, the
container is performing the update during startup of the new container.
CMK-1603
Change-Id: I2472bf21f3479d71e24c17ba5c028df3eaaae610
---
.werks/7089 | 19 ++++++++++++++++++
docker/docker-entrypoint.sh | 9 +++++++++
tests/docker/test_docker.py | 49 +++++++++++++++++----------------------------
3 files changed, 46 insertions(+), 31 deletions(-)
diff --git a/.werks/7089 b/.werks/7089
new file mode 100644
index 0000000..7231cf9
--- /dev/null
+++ b/.werks/7089
@@ -0,0 +1,19 @@
+Title: Docker container: Simplified update procedure
+Level: 2
+Component: omd
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1550474576
+Class: feature
+
+The update procedure of the official Check_MK containers was a bit complicated
+compared to the update procedure on other servers. The root cause for this was
+that the update always required both, the old and the new versions, while the
+containers are only allowed to have one version installed. This made it
+necessary to create an intermediate container for the update.
+
+The werk #7088 made it possible to perform an update without having access to
+the old version. Once we have this functionality it is now possible to replace
+one container with a another container. In case the version has changed, the
+container is performing the update during startup of the new container.
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
index b17e7fa..c6b66a8 100755
--- a/docker/docker-entrypoint.sh
+++ b/docker/docker-entrypoint.sh
@@ -58,6 +58,15 @@ if [ ! -f "/omd/apache/$CMK_SITE_ID.conf" ]; then
echo "Include /omd/sites/$CMK_SITE_ID/etc/apache/mode.conf" > "/omd/apache/$CMK_SITE_ID.conf"
fi
+# In case the version symlink is dangling we are in an update situation: The
+# volume was previously attached to a container with another Check_MK version.
+# We now have to perform the "omd update" to be able to bring the site back
+# to life.
+if [ ! -e "/omd/sites/$CMK_SITE_ID/version" ]; then
+ echo "### UPDATING SITE"
+ omd -f update --conflict=install "$CMK_SITE_ID"
+fi
+
# When a command is given via "docker run" use it instead of this script
if [ -n "$1" ]; then
exec "$@"
diff --git a/tests/docker/test_docker.py b/tests/docker/test_docker.py
index 23463dd..d42137a 100644
--- a/tests/docker/test_docker.py
+++ b/tests/docker/test_docker.py
@@ -326,41 +326,28 @@ def test_update(request, client, version):
assert c_orig.exec_run(["touch", "pre-update-marker"], user="cmk",
workdir="/omd/sites/cmk")[0] == 0
+ # Until we have a "old version" with .version_meta directory that we can update
+ # from produce this directory manually here.
+ # TODO: Once we update from a 1.6 version this can be dropped
+ assert c_orig.exec_run(["mkdir", ".version_meta"], user="cmk", workdir="/omd/sites/cmk")[0] == 0
+ assert c_orig.exec_run(["cp", "-pr", "version/skel", ".version_meta/"],
+ user="cmk",
+ workdir="/omd/sites/cmk")[0] == 0
+ assert c_orig.exec_run(["cp", "-pr", "version/share/omd/skel.permissions", ".version_meta/"],
+ user="cmk",
+ workdir="/omd/sites/cmk")[0] == 0
+ assert c_orig.exec_run(
+ ["bash", "-c", "echo '%s' > .version_meta/version" % old_version.version],
+ user="cmk",
+ workdir="/omd/sites/cmk")[0] == 0
+
# 2. stop the container
c_orig.stop()
- # 3. start intermediate container in the background and keep it running.
- # Don't use the regular startup procedure (which would start the site). Use
- # read to wait for termination of the container
- image, _build_logs = _build(request, client, version)
- c_tmp = client.containers.run(
- name="%s-update" % container_name,
- image=image.id,
- detach=True,
- command=["bash", "-c", "echo HI ; read"],
- stdin_open=True,
- volumes_from=c_orig.id,
- )
- request.addfinalizer(lambda: c_tmp.remove(force=True))
- testlib.wait_until(lambda: "HI" in c_tmp.logs(), timeout=30)
-
- # 4. Copy old version to intermediate container
- stream = c_orig.get_archive("/omd/versions/%s" % old_version.omd_version())[0]
- c_tmp.put_archive(path="/omd/versions", data=stream)
-
- # 5. update volume in intermediate container
- exit_code, output = c_tmp.exec_run(["omd", "-f", "update", "--conflict=install"], user="cmk")
- assert "Finished update." in output
- assert exit_code == 0
-
- # Verify result and stop the temporary container
- c_tmp.exec_run(["omd", "version"], user="cmk")[1].endswith("%s\n" % version.omd_version())
- c_tmp.stop()
-
- # 6. rename old container
+ # 3. rename old container
c_orig.rename("%s-old" % container_name)
- # 7. create new container
+ # 4. create new container
c_new = _start(
request,
client,
@@ -369,7 +356,7 @@ def test_update(request, client, version):
name=container_name,
volumes_from=c_orig.id)
- # 8. verify result
+ # 5. verify result
c_new.exec_run(["omd", "version"], user="cmk")[1].endswith("%s\n" % version.omd_version())
assert c_new.exec_run(["test", "-f", "pre-update-marker"], user="cmk",
workdir="/omd/sites/cmk")[0] == 0
Module: check_mk
Branch: master
Commit: 4932dd56482416d961860abb79fbbb54dae4756a
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=4932dd56482416…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Mon Feb 18 08:22:08 2019 +0100
7088 omd update can now be performed without access to source version
The "omd update" procedure, which is used to perform a version update for a
site, always needed access to the previous version, the new version and the
site.
Since this change it is now possible to perform an update without access
to the old version. This is possible becase we copy the information that
are needed to the Check_MK site during site creation.
This new mechanism can only be used when updating FROM a site that already
implements this werk.
Technical detail:
<ul>
<li>The meta files are saved for the first time during "omd create"</li>
<li>The meta files are updated to the new version during each "omd update"</li>
<li>The files are copied to the sites <tt>.version_meta</tt> directory.</li>
<li>The directory <tt>/omd/versions/[version]/skel is copied.</li>
<li>The file <tt>/omd/versions/[version]/share/omd/skel.permissions is copied.</li>
<li>A file <tt><tt>.version_meta/version</tt> is created.</li>
<li>When an update is performed, the meta files are used if they are available
and up-to-date. In case they don't fit these conditiones, the previous version
files need to be available as before this werk.</li>
<li>
CMK-1603
Change-Id: I4e448e36ce987cbfcedfa47535fab2e9b49b2c19
---
.werks/7088 | 33 ++++++++++
omd/packages/omd/omdlib/main.py | 111 +++++++++++++++++++++++++++------
tests/unit/omdlib/test_omdlib_main.py | 6 +-
tests/unit/omdlib/test_site_context.py | 6 +-
4 files changed, 131 insertions(+), 25 deletions(-)
Diff: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commitdiff;h=4932dd5648…