Module: check_mk
Branch: master
Commit: 669b0ec67a33e1b8c9e61bb2b4527cdc85b0b918
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=669b0ec67a33e1…
Author: Sven Panne <sp(a)mathias-kettner.de>
Date: Tue May 10 15:11:37 2016 +0200
Improved the Unicode story in mkeventd.
---
bin/mkeventd | 70 ++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 24 deletions(-)
diff --git a/bin/mkeventd b/bin/mkeventd
index 0393d9f..c1b4558 100755
--- a/bin/mkeventd
+++ b/bin/mkeventd
@@ -2,7 +2,7 @@
# encoding: utf-8
import socket, os, time, sys, getopt, signal, thread, pprint, re, \
- select, subprocess, stat
+ select, subprocess, stat, string
import cmk.daemon
VERSION="1.4.0i1"
@@ -94,6 +94,39 @@ history_columns = [
( "history_addinfo", "" ),
] + event_columns
+# Alas, we often have no clue about the actual encoding, so we have to guess:
+# Initially we assume UTF-8, but fall back to latin-1 if it didn't work.
+def decode_from_bytes(string_as_bytes):
+ try:
+ return string_as_bytes.decode("utf-8")
+ except:
+ return string_as_bytes.decode("latin-1")
+
+# Rip out/replace any characters which have a special meaning see in the UTF-8
+# encoded history files, see e.g. quote_tab. In theory this shouldn't be
+# necessary, because there are a bunch of bytes which are not contained in any
+# valid UTF-8 string, but following Murphy's Law, those are not used in
+# Check_MK. To keep backwards compatibility with old history files, we have no
+# choice and continue to do it wrong... :-/
+def scrub_string(s):
+ if type(s) == str:
+ return s.translate(scrub_string.str_table, "\0\1\2\n")
+ if type(s) == unicode:
+ return s.translate(scrub_string.unicode_table)
+ raise TypeError("scrub_string expects a string argument")
+
+scrub_string.str_table = string.maketrans("\t", " ")
+scrub_string.unicode_table = {
+ 0: None,
+ 1: None,
+ 2: None,
+ ord("\n"): None,
+ ord("\t"): ord(" ")
+}
+
+def scrub_and_decode(s):
+ return decode_from_bytes(scrub_string(s))
+
def unsplit(s):
if not isinstance(s, basestring):
return s
@@ -694,9 +727,9 @@ def log_event_history_to_file(event, what, who, addinfo):
with lock_logging:
columns = [
str(time.time()),
- what,
- who,
- addinfo ]
+ scrub_string(what),
+ scrub_string(who),
+ scrub_string(addinfo) ]
columns += [ quote_tab(event.get(colname[6:], defval)) # drop "event_"
for colname, defval in event_columns ]
@@ -1323,28 +1356,23 @@ class EventServer:
def create_event_from_trap(self, trap, ipaddress):
# use the trap-oid as application
- application = ''
+ application = u''
for index, (oid, val) in enumerate(trap):
if oid in ['1.3.6.1.6.3.1.1.4.1.0',
'SNMPv2-MIB::snmpTrapOID.0']:
- application = trap.pop(index)[1]
+ application = scrub_and_decode(trap.pop(index)[1])
break
# once we got here we have a real parsed trap which we convert to an event now
- text = ', '.join([ '%s: %s' % (item[0],
str(item[1]).replace('\n', '')) for item in trap ])
-
- # Convert to Unicode, first assume UTF-8, then latin-1
- try:
- text = text.decode("utf-8")
- except:
- text = text.decode("latin-1")
+ safe_ipaddress = scrub_and_decode(ipaddress)
+ text = scrub_and_decode(', '.join([ '%s: %s' % (item[0],
str(item[1])) for item in trap ]))
event = {
'time' : time.time(),
- 'host' : ipaddress,
- 'ipaddress' : ipaddress,
+ 'host' : safe_ipaddress,
+ 'ipaddress' : safe_ipaddress,
'priority' : 5, # notice
'facility' : 31, # not used by syslog -> we use this for all
traps
- 'application' : application.replace('\n', ''),
+ 'application' : application,
'text' : text
}
@@ -1509,13 +1537,7 @@ class EventServer:
def process_raw_lines(self, data, address = None):
lines = data.splitlines()
for line in lines:
- line = line.rstrip().replace('\0', '')
- # Convert to Unicode, first assume UTF-8, then latin-1
- try:
- line = line.decode("utf-8")
- except:
- line = line.decode("latin-1")
-
+ line = scrub_and_decode(line.rstrip())
if line:
try:
self.process_raw_data(self.process_line, (line, address))
@@ -2608,7 +2630,7 @@ class StatusServer:
def handle_client(self, socket, allow_commands, client_ip):
- query = socket.recv(8192).splitlines()
+ query = decode_from_bytes(socket.recv(8192)).splitlines()
parts = query[0].split(None, 1)
if len(parts) != 2:
raise MKClientError("Invalid query. Need GET/COMMAND plus
argument(s)")