Module: check_mk
Branch: master
Commit: 0dfbdce39066c545cd7dcdc715a55c68bca0dd39
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0dfbdce39066c5…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Tue Aug 25 14:12:58 2015 +0200
#2511 siemens_plc: Special agent can now be configured to fetch other memory areas than
DB
The Siemens PLC special agent was only able to fetch data from the
"Datenbaustein" memory areas.
Now it can also fetch data from Input, Output, Merker, Timer and Counter memory areas.
---
.werks/2511 | 10 ++++++
ChangeLog | 1 +
agents/special/agent_siemens_plc | 55 +++++++++++++++++++++++--------
web/plugins/wato/datasource_programs.py | 24 ++++++++++++--
4 files changed, 74 insertions(+), 16 deletions(-)
diff --git a/.werks/2511 b/.werks/2511
new file mode 100644
index 0000000..7863e32
--- /dev/null
+++ b/.werks/2511
@@ -0,0 +1,10 @@
+Title: siemens_plc: Special agent can now be configured to fetch other memory areas than
DB
+Level: 1
+Component: checks
+Compatible: compat
+Version: 1.2.7i3
+Date: 1440504698
+Class: feature
+
+The Siemens PLC special agent was only able to fetch data from the
"Datenbaustein" memory areas.
+Now it can also fetch data from Input, Output, Merker, Timer and Counter memory areas.
diff --git a/ChangeLog b/ChangeLog
index f47e153..8b67b4c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -60,6 +60,7 @@
* 1283 hyperv_checkpoints,hyperv_vmstatus: Checkpoints and Integration Services Check
for HyperV VMs...
* 2520 New check genua_vpn: monitors the VPN state of a genuscreen VPN appliance...
* 2521 new check juniper_trpz_aps_sessions: shows the radio data and sessions per
online access point...
+ * 2511 siemens_plc: Special agent can now be configured to fetch other memory areas
than DB...
* 2315 FIX: windows agent: BOM replacement, fixed incorrect byte offset...
* 2316 FIX: windows agent: fix garbled output of cached agent plugins...
* 2358 FIX: check_mk_agent.solaris: more correct computation of zfs used space...
diff --git a/agents/special/agent_siemens_plc b/agents/special/agent_siemens_plc
index 8f0d0ad..14b672c 100755
--- a/agents/special/agent_siemens_plc
+++ b/agents/special/agent_siemens_plc
@@ -27,6 +27,7 @@
import getopt, sys, socket, traceback, re, pprint
import snap7
from snap7.util import *
+from snap7.snap7types import S7AreaPE, S7AreaPA, S7AreaMK, S7AreaDB, S7AreaCT, S7AreaTM
def usage():
sys.stderr.write("""Check_MK Siemens PLC Agent
@@ -51,7 +52,9 @@ VALUES:
A value is specified by the following single data fields, which are
concatenated by a ",":
- DB_NUMBER Numeric identified of the DB
+ AREA[:DB_NUMBER] Identifier of the memory area to fetch (db, input,
+ output, merker, timer or counter), plus the optional
+ numeric identifier of the DB separeated by a
":".
ADDRESS Memory address to read
DATATYPE The datatype of the value to read
VALUETYPE The logical type of the value
@@ -112,14 +115,23 @@ for arg in args:
sys.stderr.write("ERROR: Invalid value specified: %s\n" % spec)
usage()
sys.exit(1)
+
+ if ':' in p[0]:
+ area_name, db_number = p[0].split(':')
+ area = (area_name, int(db_number))
+ else:
+ area = ("db", int(p[0]))
+
byte, bit = map(int, p[1].split('.'))
+
if ':' in p[2]:
typename, size = p[2].split(':')
datatype = typename, int(size)
else:
datatype = p[2]
- # db_number, address, datatype, valuetype, ident
- values.append((int(p[0]), (byte, bit), datatype, p[3], p[4]))
+
+ # area, address, datatype, valuetype, ident
+ values.append((area, (byte, bit), datatype, p[3], p[4]))
devices.append({
'host_name' : parts[0],
@@ -132,6 +144,7 @@ for arg in args:
socket.setdefaulttimeout(opt_timeout)
+
def get_dint(_bytearray, byte_index):
"""
Get int value from bytearray.
@@ -144,6 +157,18 @@ def get_dint(_bytearray, byte_index):
byte0 = _bytearray[byte_index]
return byte3 + (byte2 << 8) + (byte1 << 16) + (byte0 << 32)
+
+def area_name_to_area_id(name):
+ return {
+ 'db' : S7AreaDB,
+ 'input' : S7AreaPE,
+ 'output' : S7AreaPA,
+ 'merker' : S7AreaMK,
+ 'timer' : S7AreaTM,
+ 'counter' : S7AreaCT,
+ }[name]
+
+
datatypes = {
# type-name size(bytes) parse-function
# A size of None means the size is provided by configuration
@@ -167,36 +192,40 @@ for device in devices:
addresses = {}
start_address = None
end_address = None
- for db_number, (byte, bit), datatype, valuetype, ident in
device['values']:
+ for area, (byte, bit), datatype, valuetype, ident in device['values']:
if type(datatype) == tuple:
size = datatype[1]
else:
size = datatypes[datatype][0]
- addresses.setdefault(db_number, [None, None])
- start_address, end_address = addresses[db_number]
+ addresses.setdefault(area, [None, None])
+ start_address, end_address = addresses[area]
if start_address == None or byte < start_address:
- addresses[db_number][0] = byte
+ addresses[area][0] = byte
end = byte + size
if end_address == None or end > end_address:
- addresses[db_number][1] = end
+ addresses[area][1] = end
# Now fetch the data from each db number
data = {}
- for db_number, (start, end) in addresses.items():
- data[db_number] = client.db_read(db_number, start, size=end-start)
+ for (area_name, db_number), (start, end) in addresses.items():
+ area_id = area_name_to_area_id(area_name)
+ data[(area_name, db_number)] = client.read_area(area_id, db_number, start,
size=end-start)
# Now loop all values to be fetched and extract the data
# from the bytes fetched above
- for db_number, (byte, bit), datatype, valuetype, ident in
device['values']:
+ for (area_name, db_number), (byte, bit), datatype, valuetype, ident in
device['values']:
if type(datatype) == tuple:
typename, size = datatype
parse_func = datatypes[typename][1]
else:
size, parse_func = datatypes[datatype]
- data_offset = addresses[db_number][0]
- data = client.db_read(db_number, byte-data_offset, size)
+
+ data_offset = addresses[(area_name, db_number)][0]
+ area_id = area_name_to_area_id(area_name)
+
+ data = client.read_area(area_id, db_number, byte-data_offset, size)
value = parse_func(data, 0, bit)
sys.stdout.write("%s %s %s %s\n" % (device['host_name'],
valuetype, ident, value))
except:
diff --git a/web/plugins/wato/datasource_programs.py
b/web/plugins/wato/datasource_programs.py
index 3df0584..956c0f4 100644
--- a/web/plugins/wato/datasource_programs.py
+++ b/web/plugins/wato/datasource_programs.py
@@ -504,9 +504,27 @@ def validate_siemens_plc_values(value, varprefix):
valuetypes[valuetype].append(ident)
_siemens_plc_value = [
- Integer(
- title = "<nobr>%s</nobr>" % _("DB Number"),
- minvalue = 1,
+ Transform(
+ CascadingDropdown(
+ title = _("Area"),
+ choices = [
+ ("db", _("Datenbaustein"),
+ Integer(
+ title = "<nobr>%s</nobr>" % _("DB
Number"),
+ minvalue = 1,
+ )
+ ),
+ ("input", _("Input")),
+ ("output", _("Output")),
+ ("merker", _("Merker")),
+ ("timer", _("Timer")),
+ ("counter", _("Counter")),
+ ],
+ orientation = "horizontal",
+ sorted = True,
+ ),
+ # Transform old Integer() value spec to new cascading dropdown value
+ forth = lambda x: type(x) == int and ("db", x) or x,
),
Float(
title = _("Address"),