diff --git a/doc/plcsystem.html b/doc/plcsystem.html index 8a5219e..42c4fc0 100644 --- a/doc/plcsystem.html +++ b/doc/plcsystem.html @@ -46,7 +46,7 @@ Thread

Class Attributes

- +
None
autoreloaddelay

Class Methods

@@ -60,6 +60,12 @@ Methods RevPiPlc Instantiiert RevPiPlc-Klasse. +__get_autoreloaddelay +Getter fuer autoreloaddelay. + +__set_autoreloaddelay +Setter fuer autoreloaddelay. + _configureplw Konfiguriert den PipeLogwriter fuer Ausgaben der PLCAPP. @@ -90,6 +96,23 @@ RevPiPlc (Constructor) RevPiPlc(program, arguments, pversion)

Instantiiert RevPiPlc-Klasse. +

+

+RevPiPlc.__get_autoreloaddelay

+__get_autoreloaddelay() +

+Getter fuer autoreloaddelay. +

+
Returns:
+
+Delayzeit in Sekunden +
+
+

+RevPiPlc.__set_autoreloaddelay

+__set_autoreloaddelay(value) +

+Setter fuer autoreloaddelay.

RevPiPlc._configureplw

diff --git a/doc/revpipyload.html b/doc/revpipyload.html index 33187e1..e478cd8 100644 --- a/doc/revpipyload.html +++ b/doc/revpipyload.html @@ -78,6 +78,12 @@ Methods RevPiPyLoad Instantiiert RevPiPyLoad-Klasse. +_check_mustrestart_plcprogram +Prueft ob sich kritische Werte veraendert haben. + +_check_mustrestart_plcslave +Prueft ob sich kritische Werte veraendert haben. + _loadconfig Load configuration file and setup modul. @@ -105,6 +111,15 @@ Methods stop Stop revpipyload. +stop_plcprogram +Beendet PLC Programm. + +stop_plcslave +Beendet PLC Slave. + +stop_xmlrpcserver +Beendet XML-RPC. + xml_getconfig Uebertraegt die RevPiPyLoad Konfiguration. @@ -174,7 +189,29 @@ RevPiPyLoad (Constructor) RevPiPyLoad()

Instantiiert RevPiPyLoad-Klasse. -

+

+

+RevPiPyLoad._check_mustrestart_plcprogram

+_check_mustrestart_plcprogram() +

+Prueft ob sich kritische Werte veraendert haben. +

+
Returns:
+
+True, wenn Subsystemneustart noetig ist +
+
+

+RevPiPyLoad._check_mustrestart_plcslave

+_check_mustrestart_plcslave() +

+Prueft ob sich kritische Werte veraendert haben. +

+
Returns:
+
+True, wenn Subsystemneustart noetig ist +
+

RevPiPyLoad._loadconfig

_loadconfig() @@ -251,6 +288,24 @@ RevPiPyLoad.stop stop()

Stop revpipyload. +

+

+RevPiPyLoad.stop_plcprogram

+stop_plcprogram() +

+Beendet PLC Programm. +

+

+RevPiPyLoad.stop_plcslave

+stop_plcslave() +

+Beendet PLC Slave. +

+

+RevPiPyLoad.stop_xmlrpcserver

+stop_xmlrpcserver() +

+Beendet XML-RPC.

RevPiPyLoad.xml_getconfig

diff --git a/eric-revpipyload.api b/eric-revpipyload.api index b654401..11fd074 100644 --- a/eric-revpipyload.api +++ b/eric-revpipyload.api @@ -19,9 +19,12 @@ picontrolserver.RevPiSlave?1(ipacl, port=55234) picontrolserver.RevPiSlaveDev.run?4() picontrolserver.RevPiSlaveDev.stop?4() picontrolserver.RevPiSlaveDev?1(devcon, acl) +plcsystem.RevPiPlc.__get_autoreloaddelay?6() +plcsystem.RevPiPlc.__set_autoreloaddelay?6(value) plcsystem.RevPiPlc._configureplw?5() plcsystem.RevPiPlc._setuppopen?5() plcsystem.RevPiPlc._spopen?5(lst_proc) +plcsystem.RevPiPlc.autoreloaddelay?7 plcsystem.RevPiPlc.newlogfile?4() plcsystem.RevPiPlc.run?4() plcsystem.RevPiPlc.stop?4() @@ -45,6 +48,8 @@ proginit.pargs?7 proginit.picontrolreset?7 proginit.rapcatalog?7 proginit.startdir?7 +revpipyload.RevPiPyLoad._check_mustrestart_plcprogram?5() +revpipyload.RevPiPyLoad._check_mustrestart_plcslave?5() revpipyload.RevPiPyLoad._loadconfig?5() revpipyload.RevPiPyLoad._plcslave?5() revpipyload.RevPiPyLoad._plcthread?5() @@ -55,6 +60,9 @@ revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False) revpipyload.RevPiPyLoad.root?7 revpipyload.RevPiPyLoad.start?4() revpipyload.RevPiPyLoad.stop?4() +revpipyload.RevPiPyLoad.stop_plcprogram?4() +revpipyload.RevPiPyLoad.stop_plcslave?4() +revpipyload.RevPiPyLoad.stop_xmlrpcserver?4() revpipyload.RevPiPyLoad.xml_getconfig?4() revpipyload.RevPiPyLoad.xml_getfilelist?4() revpipyload.RevPiPyLoad.xml_getpictoryrsc?4() diff --git a/revpipyload.e4p b/revpipyload.e4p index e7f4e7a..d2fe227 100644 --- a/revpipyload.e4p +++ b/revpipyload.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten. - 0.6.2 + 0.6.3 Sven Sager akira@narux.de @@ -23,6 +23,8 @@ revpipyload/picontrolserver.py revpipyload/helper.py revpipyload/xrpcserver.py + revpipyload/shared/ipaclmanager.py + revpipyload/shared/__init__.py @@ -215,6 +217,7 @@ data deb dist + demo diff --git a/revpipyload/picontrolserver.py b/revpipyload/picontrolserver.py index bc207da..809a8e8 100644 --- a/revpipyload/picontrolserver.py +++ b/revpipyload/picontrolserver.py @@ -69,7 +69,7 @@ class RevPiSlave(Thread): self.exitcode = -1 # Verbindung annehmen - proginit.logger.debug("accept new connection") + proginit.logger.info("accept new connection for revpinetio") try: tup_sock = self.so.accept() except: diff --git a/revpipyload/plcsystem.py b/revpipyload/plcsystem.py index 61958ee..8bb778f 100644 --- a/revpipyload/plcsystem.py +++ b/revpipyload/plcsystem.py @@ -33,6 +33,8 @@ class RevPiPlc(Thread): super().__init__() self._arguments = arguments + self._autoreloaddelay = 5 * 2 + self._delaycounter = 5 * 2 self._evt_exit = Event() self._plw = self._configureplw() self._program = program @@ -47,6 +49,18 @@ class RevPiPlc(Thread): self.zeroonerror = False self.zeroonexit = False + def __get_autoreloaddelay(self): + """Getter fuer autoreloaddelay. + @return Delayzeit in Sekunden """ + return int(self._autoreloaddelay / 2) + + def __set_autoreloaddelay(self, value): + """Setter fuer autoreloaddelay.""" + if type(value) != int: + raise RuntimeError("parameter value must be ") + self._autoreloaddelay = value * 2 + self._delaycounter = value * 2 + def _configureplw(self): """Konfiguriert den PipeLogwriter fuer Ausgaben der PLCAPP. @return PipeLogwriter()""" @@ -132,14 +146,13 @@ class RevPiPlc(Thread): _setuprt(self._procplc.pid, self._evt_exit) # Überwachung starten - delaycounter = self.autoreloaddelay while not self._evt_exit.is_set(): # Auswerten self.exitcode = self._procplc.poll() if self.exitcode is not None: - if delaycounter == self.autoreloaddelay: + if self._delaycounter == self.autoreloaddelay: if self.exitcode > 0: # PLC Python Programm abgestürzt proginit.logger.error( @@ -165,10 +178,10 @@ class RevPiPlc(Thread): ) if not self._evt_exit.is_set() and self.autoreload: - if delaycounter > 0: - delaycounter -= 1 + if self._delaycounter > 0: + self._delaycounter -= 1 else: - delaycounter = self.autoreloaddelay + self._delaycounter = self.autoreloaddelay # Prozess neu starten self._procplc = self._spopen(lst_proc) @@ -240,3 +253,5 @@ class RevPiPlc(Thread): proginit.logger.debug("log pipes successfully closed") proginit.logger.debug("leave RevPiPlc.stop()") + + autoreloaddelay = property(__get_autoreloaddelay, __set_autoreloaddelay) diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py index 0ce57a4..509a38d 100755 --- a/revpipyload/revpipyload.py +++ b/revpipyload/revpipyload.py @@ -50,7 +50,7 @@ from time import asctime from xmlrpc.client import Binary from xrpcserver import SaveXMLRPCServer -pyloadversion = "0.6.2" +pyloadversion = "0.6.3" class RevPiPyLoad(): @@ -72,12 +72,18 @@ class RevPiPyLoad(): self.evt_loadconfig = Event() self.globalconfig = ConfigParser() self.logr = logsystem.LogReader() - self.plc = None - self.plc_pause = False self.tfile = {} self.xsrv = None self.xml_ps = None + # Berechtigungsmanger + self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) + self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4) + + # Threads/Prozesse + self.th_plcslave = None + self.plc = None + # Konfiguration laden self._loadconfig() @@ -89,19 +95,59 @@ class RevPiPyLoad(): proginit.logger.debug("leave RevPiPyLoad.__init__()") + def _check_mustrestart_plcslave(self): + """Prueft ob sich kritische Werte veraendert haben. + @return True, wenn Subsystemneustart noetig ist""" + if self.th_plcslave is None: + return True + elif "PLCSLAVE" not in self.globalconfig: + return True + else: + ip = self.globalconfig["PLCSLAVE"].get("bindip", "127.0.0.1") + if ip == "*": + ip = "" + elif ip == "": + ip = "127.0.0.1" + port = int(self.globalconfig["PLCSLAVE"].get("port", 55234)) + + return ( + self.plcslave != + int(self.globalconfig["PLCSLAVE"].get("plcslave", 0)) + or self.plcslavebindip != ip + or self.plcslaveport != port + ) + + def _check_mustrestart_plcprogram(self): + """Prueft ob sich kritische Werte veraendert haben. + @return True, wenn Subsystemneustart noetig ist""" + if self.plc is None: + return True + elif "XMLRPC" not in self.globalconfig: + return True + else: + return ( + self.plcworkdir != + self.globalconfig["DEFAULT"].get("plcworkdir", ".") + or self.plcprogram != + self.globalconfig["DEFAULT"].get("plcprogram", "none.py") + or self.plcarguments != + self.globalconfig["DEFAULT"].get("plcarguments", "") + or self.plcuid != + int(self.globalconfig["DEFAULT"].get("plcuid", 65534)) + or self.plcgid != + int(self.globalconfig["DEFAULT"].get("plcgid", 65534)) + or self.pythonversion != + int(self.globalconfig["DEFAULT"].get("pythonversion", 3)) + or self.rtlevel != + int(self.globalconfig["DEFAULT"].get("rtlevel", 0)) + ) + def _loadconfig(self): """Load configuration file and setup modul.""" proginit.logger.debug("enter RevPiPyLoad._loadconfig()") - self.evt_loadconfig.clear() - pauseproc = False - - if not self._exit: - proginit.logger.info( - "shutdown revpipyload while getting new config" - ) - self.stop() - pauseproc = True + # Subsysteme herunterfahren + self.stop_xmlrpcserver() # Konfigurationsdatei laden proginit.logger.info( @@ -109,6 +155,10 @@ class RevPiPyLoad(): ) self.globalconfig.read(proginit.globalconffile) + # Merker für Subsystem-Neustart nach laden, vor setzen + restart_plcslave = self._check_mustrestart_plcslave() + restart_plcprogram = self._check_mustrestart_plcprogram() + # Konfiguration verarbeiten [DEFAULT] self.autoreload = \ int(self.globalconfig["DEFAULT"].get("autoreload", 1)) @@ -140,12 +190,15 @@ class RevPiPyLoad(): if "PLCSLAVE" in self.globalconfig: self.plcslave = \ int(self.globalconfig["PLCSLAVE"].get("plcslave", 0)) - self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) + + # Berechtigungen laden, wenn aktiv ist if not self.plcslaveacl.loadaclfile( self.globalconfig["PLCSLAVE"].get("aclfile", "")): proginit.logger.warning( "can not load plcslave acl - wrong format" ) + if self.plcslave != 1: + self.stop_plcslave() # Bind IP lesen und anpassen self.plcslavebindip = \ @@ -163,7 +216,7 @@ class RevPiPyLoad(): if "XMLRPC" in self.globalconfig: self.xmlrpc = \ int(self.globalconfig["XMLRPC"].get("xmlrpc", 0)) - self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4) + if not self.xmlrpcacl.loadaclfile( self.globalconfig["XMLRPC"].get("aclfile", "")): proginit.logger.warning( @@ -188,12 +241,37 @@ class RevPiPyLoad(): ) os.chdir(self.plcworkdir) - # PLC Threads konfigurieren - self.plc = self._plcthread() - self.th_plcslave = self._plcslave() + # PLC Programm konfigurieren + if restart_plcprogram: + self.stop_plcprogram() + self.plc = self._plcthread() + + if not self._exit and self.plc is not None and self.autostart: + proginit.logger.info("restart plc program after reload") + self.plc.start() + + else: + proginit.logger.info( + "configure plc program parameters after reload" + ) + self.plc.autoreload = self.autoreload + self.plc.autoreloaddelay = self.autoreloaddelay + self.plc.zeroonerror = self.zeroonerror + self.plc.zeroonexit = self.zeroonexit + + # PLC-Slave konfigurieren + if restart_plcslave: + self.stop_plcslave() + self.th_plcslave = self._plcslave() + + if not self._exit and self.th_plcslave is not None: + proginit.logger.info("restart plc slave after reload") + self.th_plcslave.start() # XMLRPC-Server Instantiieren und konfigurieren - if self.xmlrpc == 1: + if self.xmlrpc == 0: + self.xmlrpc = None + else: proginit.logger.debug("create xmlrpc server") self.xsrv = SaveXMLRPCServer( (self.xmlrpcbindip, self.xmlrpcport), @@ -276,11 +354,13 @@ class RevPiPyLoad(): proginit.logger.debug("created xmlrpc server") - if pauseproc: - proginit.logger.info( - "start revpipyload after getting new config" - ) - self.start() + # Neustart bei reload + if not self._exit: + proginit.logger.info("start xmlrpc-server") + self.xsrv.start() + + # Konfiguration abschließen + self.evt_loadconfig.clear() proginit.logger.debug("leave RevPiPyLoad._loadconfig()") @@ -297,7 +377,7 @@ class RevPiPyLoad(): )) return None - proginit.logger.debug("create PLC watcher") + proginit.logger.debug("create PLC program watcher") th_plc = plcsystem.RevPiPlc( os.path.join(self.plcworkdir, self.plcprogram), self.plcarguments, @@ -423,17 +503,21 @@ class RevPiPyLoad(): # Slaveausfuehrung übergeben self.th_plcslave.start() - if self.autostart: - proginit.logger.debug("starting revpiplc-thread") - if self.plc is not None: - self.plc.start() + # PLC Programm automatisch starten + if self.autostart and self.plc is not None: + self.plc.start() - while not self._exit \ - and not self.evt_loadconfig.is_set(): + # mainloop + while not self._exit: + + # Neue Konfiguration laden + if self.evt_loadconfig.is_set(): + proginit.logger.info("got reqeust to reload config") + self._loadconfig() # PLC Server Thread prüfen - if self.plcslave \ - and not (self.plc_pause or self.th_plcslave.is_alive()): + if self.plcslave and self.th_plcslave is not None \ + and not self.th_plcslave.is_alive(): proginit.logger.warning( "restart plc slave after thread was not running" ) @@ -452,39 +536,57 @@ class RevPiPyLoad(): self.evt_loadconfig.wait(1) - if not self._exit: - proginit.logger.info("exit python plc program to reload config") - self._loadconfig() + proginit.logger.info("stopping revpipyload") + + # Alle Sub-Systeme beenden + self.stop_plcslave() + self.stop_plcprogram() + self.stop_xmlrpcserver() + + # Logreader schließen + self.logr.closeall() proginit.logger.debug("leave RevPiPyLoad.start()") def stop(self): """Stop revpipyload.""" proginit.logger.debug("enter RevPiPyLoad.stop()") - - proginit.logger.info("stopping revpipyload") self._exit = True + proginit.logger.debug("leave RevPiPyLoad.stop()") - if self.th_plcslave is not None and self.th_plcslave.is_alive(): - proginit.logger.debug("stopping revpi slave thread") - self.th_plcslave.stop() - self.th_plcslave.join() - proginit.logger.debug("revpi slave thread successfully closed") + def stop_plcprogram(self): + """Beendet PLC Programm.""" + proginit.logger.debug("enter RevPiPyLoad.stop_plcprogram()") if self.plc is not None and self.plc.is_alive(): - proginit.logger.debug("stopping revpiplc thread") + proginit.logger.info("stopping revpiplc thread") self.plc.stop() self.plc.join() proginit.logger.debug("revpiplc thread successfully closed") - if self.xmlrpc >= 1: + proginit.logger.debug("leave RevPiPyLoad.stop_plcprogram()") + + def stop_plcslave(self): + """Beendet PLC Slave.""" + proginit.logger.debug("enter RevPiPyLoad.stop_plcslave()") + + if self.th_plcslave is not None and self.th_plcslave.is_alive(): + proginit.logger.info("stopping revpi slave thread") + self.th_plcslave.stop() + self.th_plcslave.join() + proginit.logger.debug("revpi slave thread successfully closed") + + proginit.logger.debug("leave RevPiPyLoad.stop_plcslave()") + + def stop_xmlrpcserver(self): + """Beendet XML-RPC.""" + proginit.logger.debug("enter RevPiPyLoad.stop_xmlrpcserver()") + + if self.xsrv is not None: proginit.logger.info("shutting down xmlrpc-server") self.xsrv.stop() - # Logreader schließen - self.logr.closeall() - - proginit.logger.debug("leave RevPiPyLoad.stop()") + proginit.logger.debug("leave RevPiPyLoad.stop_xmlrpcserver()") def xml_getconfig(self): """Uebertraegt die RevPiPyLoad Konfiguration. @@ -618,9 +720,7 @@ class RevPiPyLoad(): """ proginit.logger.debug("xmlrpc call plcstop") if self.plc is not None and self.plc.is_alive(): - self.plc.stop() - self.plc.join() - proginit.logger.debug("revpiplc thread successfully closed") + self.stop_plcprogram() return self.plc.exitcode else: return -1 @@ -725,6 +825,13 @@ class RevPiPyLoad(): str(dc[key]) ) + # conf-Datei schreiben + with open(proginit.globalconffile, "w") as fh: + self.globalconfig.write(fh) + proginit.logger.info( + "got new config and wrote it to {}".format(proginit.globalconffile) + ) + # ACLs sofort übernehmen und schreiben str_acl = dc.get("plcslaveacl", None) if str_acl is not None and self.plcslaveacl.acl != str_acl: @@ -759,16 +866,8 @@ class RevPiPyLoad(): ) ) - # conf-Datei schreiben - with open(proginit.globalconffile, "w") as fh: - self.globalconfig.write(fh) - proginit.logger.info( - "got new config and wrote it to {}".format(proginit.globalconffile) - ) - - if loadnow: - # RevPiPyLoad neu konfigurieren - self.evt_loadconfig.set() + # RevPiPyLoad neu konfigurieren + self.evt_loadconfig.set() return True @@ -862,7 +961,6 @@ class RevPiPyLoad(): -2: Laeuft bereits """ - self.plc_pause = False if self.th_plcslave is not None and self.th_plcslave.is_alive(): return -2 else: @@ -876,9 +974,9 @@ class RevPiPyLoad(): def xml_plcslavestop(self): """Stoppt den PLC Slave Server. @return True, wenn stop erfolgreich""" - self.plc_pause = True if self.th_plcslave is not None: - self.th_plcslave.stop() + self.stop_plcslave() + self.th_plcslave = None return True else: return False diff --git a/setup.py b/setup.py index 079f00e..9565b6d 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( license="LGPLv3", name="revpipyload", - version="0.6.2", + version="0.6.3", scripts=["data/revpipyload"], @@ -39,9 +39,12 @@ setup( "data/etc/avahi/services/revpipyload.service", ]), ("/etc/revpipyload", [ + "data/etc/revpipyload/aclplcslave.conf", + "data/etc/revpipyload/aclxmlrpc.conf", "data/etc/revpipyload/revpipyload.conf", ]), ("share/revpipyload", glob("revpipyload/*.*")), + ("share/revpipyload/shared", glob("revpipyload/shared/*.*")), ("/var/lib/revpipyload", [ "data/var/lib/revpipyload/.placeholder", ])