Dateikontrolle für pictory und replace_ios per timestamp und hash Wert

Hashwerte der Dateien über RevPiNetIO abrufbar b'PH' b'RH'
Alte Testfunktion für replace_ios aus helper entfernt
This commit is contained in:
2019-08-18 11:23:18 +02:00
parent 80c2550739
commit c024020294
7 changed files with 155 additions and 160 deletions

View File

@@ -31,9 +31,6 @@ Functions</h3>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#refullmatch">refullmatch</a></td> <td><a style="color:#0000FF" href="#refullmatch">refullmatch</a></td>
<td>re.fullmatch wegen alter python version aus wheezy nachgebaut.</td> <td>re.fullmatch wegen alter python version aus wheezy nachgebaut.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#revpimodio_replaceio">revpimodio_replaceio</a></td>
<td>Importiert und ersetzt IOs in RevPiModIO.</td>
</tr> </tr>
</table> </table>
<hr /><hr /> <hr /><hr />
@@ -83,26 +80,5 @@ True, wenn komplett passt sonst False
</dd> </dd>
</dl> </dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div> <div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="revpimodio_replaceio" ID="revpimodio_replaceio"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">revpimodio_replaceio</h2>
<b>revpimodio_replaceio</b>(<i>revpi, filename</i>)
<p>
Importiert und ersetzt IOs in RevPiModIO.
</p><dl>
<dt><i>revpi</i></dt>
<dd>
RevPiModIO Instanz
</dd><dt><i>filename</i></dt>
<dd>
Dateiname der Ersetzungsdatei
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
True, wenn alle IOs ersetzt werden konnten
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /> <hr />
</body></html> </body></html>

View File

@@ -110,6 +110,12 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiPyLoad._signewlogfile">_signewlogfile</a></td> <td><a style="color:#0000FF" href="#RevPiPyLoad._signewlogfile">_signewlogfile</a></td>
<td>Signal handler to start new logfile.</td> <td>Signal handler to start new logfile.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.check_pictory_changed">check_pictory_changed</a></td>
<td>Prueft ob sich die piCtory Datei veraendert hat.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.check_replace_ios_changed">check_replace_ios_changed</a></td>
<td>Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.packapp">packapp</a></td> <td><a style="color:#0000FF" href="#RevPiPyLoad.packapp">packapp</a></td>
<td>Erzeugt aus dem PLC-Programm ein TAR/Zip-File.</td> <td>Erzeugt aus dem PLC-Programm ein TAR/Zip-File.</td>
</tr><tr> </tr><tr>
@@ -299,7 +305,29 @@ RevPiPyLoad._signewlogfile</h3>
<b>_signewlogfile</b>(<i>signum, frame</i>) <b>_signewlogfile</b>(<i>signum, frame</i>)
<p> <p>
Signal handler to start new logfile. Signal handler to start new logfile.
</p><a NAME="RevPiPyLoad.packapp" ID="RevPiPyLoad.packapp"></a> </p><a NAME="RevPiPyLoad.check_pictory_changed" ID="RevPiPyLoad.check_pictory_changed"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.check_pictory_changed</h3>
<b>check_pictory_changed</b>(<i></i>)
<p>
Prueft ob sich die piCtory Datei veraendert hat.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn veraendert wurde
</dd>
</dl><a NAME="RevPiPyLoad.check_replace_ios_changed" ID="RevPiPyLoad.check_replace_ios_changed"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.check_replace_ios_changed</h3>
<b>check_replace_ios_changed</b>(<i></i>)
<p>
Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn veraendert wurde
</dd>
</dl><a NAME="RevPiPyLoad.packapp" ID="RevPiPyLoad.packapp"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.packapp</h3> RevPiPyLoad.packapp</h3>
<b>packapp</b>(<i>mode="tar", pictory=False</i>) <b>packapp</b>(<i>mode="tar", pictory=False</i>)

View File

@@ -4,7 +4,6 @@ helper.__license__?9
helper._setuprt?5(pid, evt_exit) helper._setuprt?5(pid, evt_exit)
helper._zeroprocimg?5() helper._zeroprocimg?5()
helper.refullmatch?4(regex, string) helper.refullmatch?4(regex, string)
helper.revpimodio_replaceio?4(revpi, filename)
logsystem.LogReader.closeall?4() logsystem.LogReader.closeall?4()
logsystem.LogReader.load_applog?4(start, count) logsystem.LogReader.load_applog?4(start, count)
logsystem.LogReader.load_plclog?4(start, count) logsystem.LogReader.load_plclog?4(start, count)
@@ -93,6 +92,8 @@ revpipyload.RevPiPyLoad._plcthread?5()
revpipyload.RevPiPyLoad._sigexit?5(signum, frame) revpipyload.RevPiPyLoad._sigexit?5(signum, frame)
revpipyload.RevPiPyLoad._sigloadconfig?5(signum, frame) revpipyload.RevPiPyLoad._sigloadconfig?5(signum, frame)
revpipyload.RevPiPyLoad._signewlogfile?5(signum, frame) revpipyload.RevPiPyLoad._signewlogfile?5(signum, frame)
revpipyload.RevPiPyLoad.check_pictory_changed?4()
revpipyload.RevPiPyLoad.check_replace_ios_changed?4()
revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False) revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False)
revpipyload.RevPiPyLoad.start?4() revpipyload.RevPiPyLoad.start?4()
revpipyload.RevPiPyLoad.stop?4() revpipyload.RevPiPyLoad.stop?4()

View File

@@ -5,7 +5,6 @@ __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "GPLv3" __license__ = "GPLv3"
import os import os
import proginit import proginit
from configparser import ConfigParser
from re import match as rematch from re import match as rematch
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
@@ -118,115 +117,6 @@ def _zeroprocimg():
) )
def revpimodio_replaceio(revpi, filename):
"""Importiert und ersetzt IOs in RevPiModIO.
@param revpi RevPiModIO Instanz
@param filename Dateiname der Ersetzungsdatei
@return True, wenn alle IOs ersetzt werden konnten
"""
cp = ConfigParser()
try:
with open(filename, "r") as fh:
cp.read_file(fh)
except Exception as e:
proginit.logger.error(
"could not read replace_io file '{0}' | {1}".format(filename, e)
)
return False
# Pre-check
lst_replace = []
rc = True
for io in cp:
if io == "DEFAULT":
continue
dict_replace = {
"replace": cp[io].get("replace", ""),
"frm": cp[io].get("frm"),
"bmk": cp[io].get("bmk", ""),
"byteorder": cp[io].get("byteorder", "little"),
}
if dict_replace["replace"] in revpi.io:
# Byteorder prüfen
if not (dict_replace["byteorder"] == "little" or
dict_replace["byteorder"] == "big"):
proginit.logger.error(
"byteorder of '{0}' must be 'little' or 'big'".format(io)
)
rc = False
continue
if dict_replace["frm"] == "?":
# Convert defaultvalue from config file
try:
dict_replace["default"] = cp[io].getboolean("defaultvalue")
except Exception:
proginit.logger.error(
"could not convert '{0}' defaultvalue '{1}' to boolean"
"".format(io, cp[io].get("defaultvalue"))
)
rc = False
continue
# Get bitaddress
try:
dict_replace["bitaddress"] = cp[io].getint("bitaddress", 0)
except Exception:
proginit.logger.error(
"could not convert '{0}' bitaddress '{1}' to integer"
"".format(io, cp[io].get("bitaddress"))
)
rc = False
continue
else:
# Convert defaultvalue from config file
try:
dict_replace["default"] = cp[io].getint("defaultvalue")
except Exception:
proginit.logger.error(
"could not convert '{0}' defaultvalue '{1}' to integer"
"".format(io, cp[io].get("defaultvalue"))
)
rc = False
continue
else:
proginit.logger.error(
"can not find io '{0}' to replace with '{1}'"
"".format(dict_replace["replace"], io)
)
rc = False
continue
# Replace_IO übernehmen
lst_replace.append(dict_replace)
if not rc:
# Abbrechen, wenn IO-Verarbeitung einen Fehler hatte
return False
# Replace IOs
for dict_replace in lst_replace:
# FIXME: Hier können Fehler auftreten !!!
revpi.io[dict_replace["replace"]].replace_io(
io,
frm=dict_replace["frm"],
bmk=dict_replace["bmk"],
bit=dict_replace["bitaddress"],
byteorder=dict_replace["byteorder"],
defaultvalue=dict_replace["default"]
)
def refullmatch(regex, string): def refullmatch(regex, string):
"""re.fullmatch wegen alter python version aus wheezy nachgebaut. """re.fullmatch wegen alter python version aus wheezy nachgebaut.

View File

@@ -6,6 +6,7 @@ __license__ = "GPLv3"
import proginit import proginit
import socket import socket
from fcntl import ioctl from fcntl import ioctl
from hashlib import md5
from shared.ipaclmanager import IpAclManager from shared.ipaclmanager import IpAclManager
from threading import Event, Thread from threading import Event, Thread
from timeit import default_timer from timeit import default_timer
@@ -385,6 +386,25 @@ class RevPiSlaveDev(Thread):
# End-of-Transmission character immer senden # End-of-Transmission character immer senden
self._devcon.send(b'\x04') self._devcon.send(b'\x04')
elif cmd == b'PH':
# piCtory md5 Hashwert senden (32 Byte)
try:
with open(proginit.pargs.configrsc, "rb") as fh_pic:
# Hashwert erzeugen und senden
file_hash = md5(fh_pic.read())
proginit.logger.debug(
"send pictory hashvalue: {0}"
"".format(file_hash)
)
self._devcon.sendall(file_hash)
except Exception as e:
proginit.logger.error(
"error on pictory hash value transfair: {0}".format(e)
)
break
else:
continue
elif cmd == b'RP': elif cmd == b'RP':
# piCtory Konfiguration senden # piCtory Konfiguration senden
proginit.logger.debug( proginit.logger.debug(
@@ -408,6 +428,27 @@ class RevPiSlaveDev(Thread):
# End-of-Transmission character immer senden # End-of-Transmission character immer senden
self._devcon.send(b'\x04') self._devcon.send(b'\x04')
elif cmd == b'RH':
# Replace_IOs md5 Hashwert senden (32 Byte)
replace_ios = proginit.conf["DEFAULT"].get("replace_ios", None)
try:
with open(replace_ios, "rb") as fh:
# Hashwert erzeugen und senden
file_hash = md5(fh.read())
proginit.logger.debug(
"send replace_ios hashvalue: {0}"
"".format(file_hash)
)
self._devcon.sendall(file_hash)
except Exception as e:
proginit.logger.error(
"error on replace_ios hash value transfair: {0}"
"".format(e)
)
break
else:
continue
elif cmd == b'EX': elif cmd == b'EX':
# Sauber Verbindung verlassen # Sauber Verbindung verlassen
dirty = False dirty = False
@@ -429,7 +470,6 @@ class RevPiSlaveDev(Thread):
break break
try: try:
# FIXME: IOCTL für Dateien implementieren
if proginit.pargs.procimg == "/dev/piControl0": if proginit.pargs.procimg == "/dev/piControl0":
# Läuft auf RevPi # Läuft auf RevPi
ioctl(fh_proc, request, arg) ioctl(fh_proc, request, arg)
@@ -439,6 +479,7 @@ class RevPiSlaveDev(Thread):
) )
else: else:
# Simulation # Simulation
# TODO: IOCTL für Dateien implementieren
proginit.logger.warning( proginit.logger.warning(
"ioctl {0} with {1} simulated".format(request, arg) "ioctl {0} with {1} simulated".format(request, arg)
) )

View File

@@ -39,6 +39,7 @@ import signal
import tarfile import tarfile
import zipfile import zipfile
from configparser import ConfigParser from configparser import ConfigParser
from hashlib import md5
from helper import refullmatch from helper import refullmatch
from json import loads as jloads from json import loads as jloads
from shared.ipaclmanager import IpAclManager from shared.ipaclmanager import IpAclManager
@@ -49,7 +50,7 @@ from time import asctime
from xmlrpc.client import Binary from xmlrpc.client import Binary
from xrpcserver import SaveXMLRPCServer from xrpcserver import SaveXMLRPCServer
min_revpimodio = "2.3.3" min_revpimodio = "2.4.1"
class RevPiPyLoad(): class RevPiPyLoad():
@@ -67,8 +68,6 @@ class RevPiPyLoad():
# Klassenattribute # Klassenattribute
self._exit = True self._exit = True
self.pictorymtime = os.path.getmtime(proginit.pargs.configrsc)
self.replaceiosmtime = 0
self.evt_loadconfig = Event() self.evt_loadconfig = Event()
self.globalconfig = ConfigParser() self.globalconfig = ConfigParser()
proginit.conf = self.globalconfig proginit.conf = self.globalconfig
@@ -76,6 +75,12 @@ class RevPiPyLoad():
self.xsrv = None self.xsrv = None
self.xml_ps = None self.xml_ps = None
# Dateimerker
self.pictorymtime = 0
self.pictoryhash = b''
self.replaceiosmtime = 0
self.replaceiohash = b''
# Berechtigungsmanger # Berechtigungsmanger
if proginit.pargs.developermode: if proginit.pargs.developermode:
self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=9) self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=9)
@@ -233,23 +238,17 @@ class RevPiPyLoad():
self.zeroonexit = \ self.zeroonexit = \
self.globalconfig["DEFAULT"].getboolean("zeroonexit", True) self.globalconfig["DEFAULT"].getboolean("zeroonexit", True)
# MTime für replace io übernehmen # Dateiveränderungen prüfen
mtime = 0 file_changed = False
if self.replace_ios_config: # Beide Funktionen müssen einmal aufgerufen werden
if os.access(self.replace_ios_config, os.R_OK | os.W_OK): if self.check_pictory_changed():
mtime = os.path.getmtime(self.replace_ios_config) file_changed = True
else: if self.check_replace_ios_changed():
proginit.logger.error( file_changed = True
"can not access (r/w) the replace_ios file '{0}' " if file_changed:
"using defaults".format(self.replace_ios_config)
)
self.replace_ios_config = ""
if self.replaceiosmtime != mtime:
# MQTT reload erforderlich
restart_plcmqtt = True restart_plcmqtt = True
restart_plcslave = True
self.replaceiosmtime = mtime restart_plcprogram = True
# Konfiguration verarbeiten [MQTT] # Konfiguration verarbeiten [MQTT]
self.mqtt = 0 self.mqtt = 0
@@ -597,6 +596,56 @@ class RevPiPyLoad():
proginit.logger.debug("leave RevPiPyLoad._signewlogfile()") proginit.logger.debug("leave RevPiPyLoad._signewlogfile()")
def check_pictory_changed(self):
"""Prueft ob sich die piCtory Datei veraendert hat.
@return True, wenn veraendert wurde"""
mtime = os.path.getmtime(proginit.pargs.configrsc)
if self.pictorymtime == mtime:
return False
self.pictorymtime = mtime
with open(proginit.pargs.configrsc, "rb") as fh:
file_hash = md5(fh.read())
if self.pictoryhash == file_hash:
return False
self.pictoryhash = file_hash
return True
def check_replace_ios_changed(self):
"""Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).
@return True, wenn veraendert wurde"""
# Zugriffsrechte prüfen (pre-check für unten)
if self.replace_ios_config \
and not os.access(self.replace_ios_config, os.R_OK | os.W_OK):
proginit.logger.error(
"can not access (r/w) the replace_ios file '{0}' "
"using defaults".format(self.replace_ios_config)
)
self.replace_ios_config = ""
if not self.replace_ios_config:
# Dateipfad leer, prüfen ob es vorher einen gab
if self.replaceiosmtime > 0 or self.replaceiohash:
self.replaceiosmtime = 0
self.replaceiohash = b''
return True
else:
mtime = os.path.getmtime(self.replace_ios_config)
if self.replaceiosmtime == mtime:
return False
self.replaceiosmtime = mtime
with open(self.replace_ios_config, "rb") as fh:
file_hash = md5(fh.read())
if self.replaceiohash == file_hash:
return False
self.replaceiohash = file_hash
return True
def packapp(self, mode="tar", pictory=False): def packapp(self, mode="tar", pictory=False):
"""Erzeugt aus dem PLC-Programm ein TAR/Zip-File. """Erzeugt aus dem PLC-Programm ein TAR/Zip-File.
@@ -672,6 +721,7 @@ class RevPiPyLoad():
self.plc.start() self.plc.start()
# mainloop # mainloop
file_changed = False
while not self._exit: while not self._exit:
# Neue Konfiguration laden # Neue Konfiguration laden
@@ -699,21 +749,30 @@ class RevPiPyLoad():
if self.th_plcslave is not None: if self.th_plcslave is not None:
self.th_plcslave.start() self.th_plcslave.start()
# piCtory auf Veränderung prüfen # Dateiveränderungen prüfen mit beiden Funktionen!
if self.pictorymtime != os.path.getmtime(proginit.pargs.configrsc): if self.check_pictory_changed():
file_changed = True
proginit.logger.warning("piCtory configuration was changed") proginit.logger.warning("piCtory configuration was changed")
self.pictorymtime = os.path.getmtime(proginit.pargs.configrsc) if self.check_replace_ios_changed():
file_changed = True
proginit.logger.warning("replace ios file was changed")
if file_changed:
file_changed = False
# Auf Dateiveränderung reagieren
# MQTT Publisher neu laden # MQTT Publisher neu laden
if self.mqtt and self.th_plcmqtt is not None: if self.mqtt and self.th_plcmqtt is not None:
self.th_plcmqtt.reload_revpimodio() self.th_plcmqtt.reload_revpimodio()
# FIXME: ProcImgServer muss alle Verbindungen vernichten # FIXME: ProcImgServer muss alle Verbindungen vernichten
# NOTE: RevPiNetIO müsste bei Neuverbindung Hashs abfragen
# XML Prozessabbildserver neu laden # XML Prozessabbildserver neu laden
if self.xml_ps is not None: if self.xml_ps is not None:
self.xml_psstop() self.xml_psstop()
self.xml_ps.loadrevpimodio() self.xml_ps.loadrevpimodio()
# Kein psstart um Reload im Client zu erzeugen
self.evt_loadconfig.wait(1) self.evt_loadconfig.wait(1)

View File

@@ -41,7 +41,7 @@ class TestSystem:
rpi = revpimodio2.RevPiModIO( rpi = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg, procimg=proginit.pargs.procimg,
monitoring=False, monitoring=True,
debug=True, debug=True,
replace_io_file=file, replace_io_file=file,
) )