From fe05ccdc5483c64af38247c5c8636d1657b6f9a7 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 12 Mar 2018 10:56:06 +0100 Subject: [PATCH] =?UTF-8?q?IpAclManager.loadacl=20hinzugef=C3=BCgt=20IpAcl?= =?UTF-8?q?Manager.valid=5Facl=5Fstring=20entfernt=20SaveXMLRPCServer=20?= =?UTF-8?q?=C3=BCbernimmt=20ACL=20Level=20bei=20Funktionsregistrierung=20S?= =?UTF-8?q?aveXMLRPCServer=20=5Fdispatch=20werte=20ACL=20Level=20der=20Met?= =?UTF-8?q?hode=20aus=20Konfigdatei=20mit=20neuen=20Sektionen=20PLCSLAVE?= =?UTF-8?q?=20und=20XMLRPC=20versehen=20Parameter=20autoreloaddelay=20f?= =?UTF-8?q?=C3=BCr=20PLC-Neustart=20integriert=20ACL=20Vergabe=20f=C3=BCr?= =?UTF-8?q?=20alle=20register=5Ffunction=20Aufrufe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/etc/revpipyload/revpipyload.conf | 17 ++- doc/helper.html | 20 +-- doc/xrpcserver.html | 44 +++++- eric-revpipyload.api | 4 +- revpipyload/helper.py | 15 +- revpipyload/procimgserver.py | 11 +- revpipyload/revpipyload.py | 199 +++++++++++++++----------- revpipyload/xrpcserver.py | 48 ++++++- 8 files changed, 242 insertions(+), 116 deletions(-) diff --git a/data/etc/revpipyload/revpipyload.conf b/data/etc/revpipyload/revpipyload.conf index 71ed1ab..89ccd4d 100644 --- a/data/etc/revpipyload/revpipyload.conf +++ b/data/etc/revpipyload/revpipyload.conf @@ -1,17 +1,24 @@ [DEFAULT] autoreload = 1 +autoreloaddelay = 5 autostart = 1 plcworkdir = /var/lib/revpipyload plcprogram = program.py plcarguments = plcuid = 1000 plcgid = 1000 -plcslave = 0 -plcslaveacl = -plcslaveport = 55234 pythonversion = 3 rtlevel = 0 -xmlrpc = 0 -xmlrpcacl = zeroonerror = 0 zeroonexit = 0 + +[PLCSLAVE] +plcslave = 0 +acl = +bindip = * +port = 55234 + +[XMLRPC] +xmlrpc = 0 +acl = +bindip = * diff --git a/doc/helper.html b/doc/helper.html index 5a3e665..fac8094 100644 --- a/doc/helper.html +++ b/doc/helper.html @@ -74,8 +74,8 @@ Methods get_acllevel Prueft IP gegen ACL List und gibt ACL-Wert aus. -valid_acl_string -Prueft ob ein ACL-String gueltig ist. +loadacl +Laed ACL String und gibt erfolg zurueck.

@@ -135,17 +135,21 @@ zum pruefen
ACL Wert oder -1 wenn nicht gefunden
- +

-IpAclManager.valid_acl_string

-valid_acl_string(str_acl) +IpAclManager.loadacl +loadacl(str_acl)

-Prueft ob ein ACL-String gueltig ist. +Laed ACL String und gibt erfolg zurueck.

str_acl
- zum ueberpruefen - return ACL Level als +ACL als +
+
+
Returns:
+
+True, wenn erfolgreich uebernommen
Up
diff --git a/doc/xrpcserver.html b/doc/xrpcserver.html index ed0f8c0..8ff5aec 100644 --- a/doc/xrpcserver.html +++ b/doc/xrpcserver.html @@ -101,9 +101,15 @@ Methods SaveXMLRPCServer Init SaveXMLRPCServer class. +_dispatch +Prueft ACL Level fuer angeforderte Methode. + isAlive Prueft ob der XML RPC Server laeuft. +register_function +Override register_function to add acl_level. + start Startet den XML-RPC Server. @@ -122,7 +128,26 @@ SaveXMLRPCServer (Constructor) SaveXMLRPCServer(addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=IpAclManager())

Init SaveXMLRPCServer class. -

+

+

+SaveXMLRPCServer._dispatch

+_dispatch(method, params) +

+Prueft ACL Level fuer angeforderte Methode. +

+
method
+
+Angeforderte Methode +
params
+
+Argumente fuer Methode +
+
+
Returns:
+
+Dispatched data +
+

SaveXMLRPCServer.isAlive

isAlive() @@ -133,6 +158,23 @@ Prueft ob der XML RPC Server laeuft.
True, wenn Server noch laeuft
+ +

+SaveXMLRPCServer.register_function

+register_function(acl_level, function, name=None) +

+Override register_function to add acl_level. +

+
acl_level
+
+ACL level to call this function +
function
+
+Function to register +
name
+
+Alternative name to use +

SaveXMLRPCServer.start

diff --git a/eric-revpipyload.api b/eric-revpipyload.api index 382abc0..a6a64d2 100644 --- a/eric-revpipyload.api +++ b/eric-revpipyload.api @@ -3,8 +3,8 @@ helper.IpAclManager.__get_regex_acl?6() helper.IpAclManager.__set_acl?6(value) helper.IpAclManager.acl?7 helper.IpAclManager.get_acllevel?4(ipaddress) +helper.IpAclManager.loadacl?4(str_acl) helper.IpAclManager.regex_acl?7 -helper.IpAclManager.valid_acl_string?4(str_acl) helper.IpAclManager?1(acl=None, minlevel=0, maxlevel=0) helper._setuprt?5(pid, evt_exit) helper._zeroprocimg?5() @@ -85,7 +85,9 @@ revpipyload.RevPiPyLoad.xml_setpictoryrsc?4(filebytes, reset=False) revpipyload.RevPiPyLoad?1() revpipyload.pyloadversion?7 xrpcserver.SaveXMLRPCRequestHandler.parse_request?4() +xrpcserver.SaveXMLRPCServer._dispatch?5(method, params) xrpcserver.SaveXMLRPCServer.isAlive?4() +xrpcserver.SaveXMLRPCServer.register_function?4(acl_level, function, name=None) xrpcserver.SaveXMLRPCServer.start?4() xrpcserver.SaveXMLRPCServer.stop?4() xrpcserver.SaveXMLRPCServer?1(addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=IpAclManager()) diff --git a/revpipyload/helper.py b/revpipyload/helper.py index 870bc96..2e9e3bc 100644 --- a/revpipyload/helper.py +++ b/revpipyload/helper.py @@ -50,7 +50,7 @@ class IpAclManager(): if type(value) != str: raise ValueError("parameter acl must be ") - if not self.valid_acl_string(value): + if not refullmatch(self.__re_ipacl, value): raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") # Klassenwerte übernehmen @@ -82,11 +82,14 @@ class IpAclManager(): return -1 - def valid_acl_string(self, str_acl): - """Prueft ob ein ACL-String gueltig ist. - @param str_acl zum ueberpruefen - return ACL Level als """ - return refullmatch(self.__re_ipacl, str_acl) + def loadacl(self, str_acl): + """Laed ACL String und gibt erfolg zurueck. + @param str_acl ACL als + @return True, wenn erfolgreich uebernommen""" + if refullmatch(self.__re_ipacl, str_acl): + self.__set_acl(str_acl) + return True + return False acl = property(__get_acl, __set_acl) regex_acl = property(__get_regex_acl) diff --git a/revpipyload/procimgserver.py b/revpipyload/procimgserver.py index a2cb0b7..cf86d95 100644 --- a/revpipyload/procimgserver.py +++ b/revpipyload/procimgserver.py @@ -173,13 +173,12 @@ class ProcimgServer(): # Registriere Funktionen for xmlfunc in self.xmlreadfuncs: self.xmlsrv.register_function( - self.xmlreadfuncs[xmlfunc], xmlfunc + 1, self.xmlreadfuncs[xmlfunc], xmlfunc + ) + for xmlfunc in self.xmlwritefuncs: + self.xmlsrv.register_function( + 3, self.xmlwritefuncs[xmlfunc], xmlfunc ) - if self.acl >= 3: - for xmlfunc in self.xmlwritefuncs: - self.xmlsrv.register_function( - self.xmlwritefuncs[xmlfunc], xmlfunc - ) ec = True proginit.logger.debug("leave ProcimgServer.start()") diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py index 75839b7..7e30af5 100755 --- a/revpipyload/revpipyload.py +++ b/revpipyload/revpipyload.py @@ -108,50 +108,78 @@ class RevPiPyLoad(): ) self.globalconfig.read(proginit.globalconffile) - # Konfiguration verarbeiten + # Konfiguration verarbeiten [DEFAULT] self.autoreload = \ int(self.globalconfig["DEFAULT"].get("autoreload", 1)) + self.autoreloaddelay = \ + int(self.globalconfig["DEFAULT"].get("autoreloaddelay", 5)) self.autostart = \ int(self.globalconfig["DEFAULT"].get("autostart", 0)) - self.plcprog = \ + self.plcworkdir = \ + self.globalconfig["DEFAULT"].get("plcworkdir", ".") + self.plcprogram = \ self.globalconfig["DEFAULT"].get("plcprogram", "none.py") self.plcarguments = \ self.globalconfig["DEFAULT"].get("plcarguments", "") - self.plcworkdir = \ - self.globalconfig["DEFAULT"].get("plcworkdir", ".") - - # PLC Slave ACL laden und prüfen - self.plcslave = \ - int(self.globalconfig["DEFAULT"].get("plcslave", 0)) - self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) - str_acl = self.globalconfig["DEFAULT"].get("plcslaveacl", "") - if not self.plcslaveacl.valid_acl_string(str_acl): - proginit.logger.warning("can not load plcslaveacl - wrong format") - else: - self.plcslaveacl.acl = str_acl - self.plcslaveport = \ - int(self.globalconfig["DEFAULT"].get("plcslaveport", 55234)) - - self.pythonver = \ + self.plcuid = \ + int(self.globalconfig["DEFAULT"].get("plcuid", 65534)) + self.plcgid = \ + int(self.globalconfig["DEFAULT"].get("plcgid", 65534)) + self.pythonversion = \ int(self.globalconfig["DEFAULT"].get("pythonversion", 3)) self.rtlevel = \ int(self.globalconfig["DEFAULT"].get("rtlevel", 0)) - - # XML ACL laden und prüfen - self.xmlrpc = \ - int(self.globalconfig["DEFAULT"].get("xmlrpc", 0)) - self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=3) - str_acl = self.globalconfig["DEFAULT"].get("xmlrpcacl", "") - if not self.xmlrpcacl.valid_acl_string(str_acl): - proginit.logger.warning("can not load xmlrpcacl - wrong format") - else: - self.xmlrpcacl.acl = str_acl - self.zeroonerror = \ int(self.globalconfig["DEFAULT"].get("zeroonerror", 1)) self.zeroonexit = \ int(self.globalconfig["DEFAULT"].get("zeroonexit", 1)) + # Konfiguration verarbeiten [PLCSLAVE] + self.plcslave = 0 + if "PLCSLAVE" in self.globalconfig: + self.plcslave = \ + int(self.globalconfig["PLCSLAVE"].get("plcslave", 0)) + self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) + if not self.plcslaveacl.loadacl( + self.globalconfig["PLCSLAVE"].get("acl", "")): + proginit.logger.warning( + "can not load plcslave acl - wrong format" + ) + + # Bind IP lesen und anpassen + self.plcslavebindip = \ + self.globalconfig["PLCSLAVE"].get("bindip", "127.0.0.1") + if self.plcslavebindip == "*": + self.plcslavebindip = "" + elif self.plcslavebindip == "": + self.plcslavebindip = "127.0.0.1" + + self.plcslaveport = \ + int(self.globalconfig["PLCSLAVE"].get("port", 55234)) + + # Konfiguration verarbeiten [XMLRPC] + self.xmlrpc = 0 + if "XMLRPC" in self.globalconfig: + self.xmlrpc = \ + int(self.globalconfig["XMLRPC"].get("xmlrpc", 0)) + self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=3) + if not self.xmlrpcacl.loadacl( + self.globalconfig["XMLRPC"].get("acl", "")): + proginit.logger.warning( + "can not load xmlrpc acl - wrong format" + ) + + # Bind IP lesen und anpassen + self.xmlrpcbindip = \ + self.globalconfig["XMLRPC"].get("bindip", "127.0.0.1") + if self.xmlrpcbindip == "*": + self.xmlrpcbindip = "" + elif self.xmlrpcbindip == "": + self.xmlrpcbindip = "127.0.0.1" + + self.xmlrpcport = \ + int(self.globalconfig["XMLRPC"].get("port", 55123)) + # Workdirectory wechseln if not os.access(self.plcworkdir, os.R_OK | os.W_OK | os.X_OK): raise ValueError( @@ -159,18 +187,15 @@ class RevPiPyLoad(): ) os.chdir(self.plcworkdir) - # PLC Thread konfigurieren + # PLC Threads konfigurieren self.plc = self._plcthread() self.th_plcslave = self._plcslave() # XMLRPC-Server Instantiieren und konfigurieren - if self.xmlrpc >= 1: + if self.xmlrpc == 1: proginit.logger.debug("create xmlrpc server") self.xsrv = SaveXMLRPCServer( - ( - "", - int(self.globalconfig["DEFAULT"].get("xmlrpcport", 55123)) - ), + (self.xmlrpcbindip, self.xmlrpcport), logRequests=False, allow_none=True, ipacl=self.xmlrpcacl @@ -178,17 +203,27 @@ class RevPiPyLoad(): self.xsrv.register_introspection_functions() self.xsrv.register_multicall_functions() + # Allgemeine Funktionen + self.xsrv.register_function(0, lambda: pyloadversion, "version") + self.xsrv.register_function(0, lambda acl: acl, "xmlmodus") + # XML Modus 1 Nur Logs lesen und PLC Programm neu starten - self.xsrv.register_function(self.logr.load_applog, "load_applog") - self.xsrv.register_function(self.logr.load_plclog, "load_plclog") - self.xsrv.register_function(self.xml_plcexitcode, "plcexitcode") - self.xsrv.register_function(self.xml_plcrunning, "plcrunning") - self.xsrv.register_function(self.xml_plcstart, "plcstart") - self.xsrv.register_function(self.xml_plcstop, "plcstop") - self.xsrv.register_function(self.xml_reload, "reload") self.xsrv.register_function( - self.xml_plcslaverunning, "plcslaverunning" - ) + 0, self.logr.load_applog, "load_applog") + self.xsrv.register_function( + 0, self.logr.load_plclog, "load_plclog") + self.xsrv.register_function( + 0, self.xml_plcexitcode, "plcexitcode") + self.xsrv.register_function( + 0, self.xml_plcrunning, "plcrunning") + self.xsrv.register_function( + 0, self.xml_plcstart, "plcstart") + self.xsrv.register_function( + 0, self.xml_plcstop, "plcstop") + self.xsrv.register_function( + 0, self.xml_reload, "reload") + self.xsrv.register_function( + 0, self.xml_plcslaverunning, "plcslaverunning") # Erweiterte Funktionen anmelden try: @@ -196,8 +231,8 @@ class RevPiPyLoad(): self.xml_ps = procimgserver.ProcimgServer( self.xsrv, self.xmlrpc ) - self.xsrv.register_function(self.xml_psstart, "psstart") - self.xsrv.register_function(self.xml_psstop, "psstop") + self.xsrv.register_function(1, self.xml_psstart, "psstart") + self.xsrv.register_function(1, self.xml_psstop, "psstop") except: self.xml_ps = None proginit.logger.warning( @@ -208,38 +243,36 @@ class RevPiPyLoad(): ) # XML Modus 2 Einstellungen lesen und Programm herunterladen - if self.xmlrpc >= 2: - self.xsrv.register_function( - self.xml_getconfig, "get_config") - self.xsrv.register_function( - self.xml_getfilelist, "get_filelist") - self.xsrv.register_function( - self.xml_getpictoryrsc, "get_pictoryrsc") - self.xsrv.register_function( - self.xml_getprocimg, "get_procimg") - self.xsrv.register_function( - self.xml_plcdownload, "plcdownload") + self.xsrv.register_function( + 2, self.xml_getconfig, "get_config") + self.xsrv.register_function( + 2, self.xml_getfilelist, "get_filelist") + self.xsrv.register_function( + 2, self.xml_getpictoryrsc, "get_pictoryrsc") + self.xsrv.register_function( + 2, self.xml_getprocimg, "get_procimg") + self.xsrv.register_function( + 2, self.xml_plcdownload, "plcdownload") # XML Modus 3 Programm und Konfiguration hochladen - if self.xmlrpc >= 3: - self.xsrv.register_function( - self.xml_plcupload, "plcupload") - self.xsrv.register_function( - self.xml_plcuploadclean, "plcuploadclean") - self.xsrv.register_function( - lambda: os.system(proginit.picontrolreset), - "resetpicontrol") - self.xsrv.register_function( - self.xml_plcslavestart, "plcslavestart") - self.xsrv.register_function( - self.xml_plcslavestop, "plcslavestop") - self.xsrv.register_function( - self.xml_setconfig, "set_config") - self.xsrv.register_function( - self.xml_setpictoryrsc, "set_pictoryrsc") + self.xsrv.register_function( + 3, self.xml_plcupload, "plcupload") + self.xsrv.register_function( + 3, self.xml_plcuploadclean, "plcuploadclean") + self.xsrv.register_function( + 3, + lambda: os.system(proginit.picontrolreset), + "resetpicontrol" + ) + self.xsrv.register_function( + 3, self.xml_plcslavestart, "plcslavestart") + self.xsrv.register_function( + 3, self.xml_plcslavestop, "plcslavestop") + self.xsrv.register_function( + 3, self.xml_setconfig, "set_config") + self.xsrv.register_function( + 3, self.xml_setpictoryrsc, "set_pictoryrsc") - self.xsrv.register_function(lambda: pyloadversion, "version") - self.xsrv.register_function(lambda: self.xmlrpc, "xmlmodus") proginit.logger.debug("created xmlrpc server") if pauseproc: @@ -257,21 +290,21 @@ class RevPiPyLoad(): th_plc = None # Prüfen ob Programm existiert - if not os.path.exists(os.path.join(self.plcworkdir, self.plcprog)): + if not os.path.exists(os.path.join(self.plcworkdir, self.plcprogram)): proginit.logger.error("plc file does not exists {}".format( - os.path.join(self.plcworkdir, self.plcprog) + os.path.join(self.plcworkdir, self.plcprogram) )) return None proginit.logger.debug("create PLC watcher") th_plc = plcsystem.RevPiPlc( - os.path.join(self.plcworkdir, self.plcprog), + os.path.join(self.plcworkdir, self.plcprogram), self.plcarguments, - self.pythonver + self.pythonversion ) th_plc.autoreload = self.autoreload - th_plc.gid = int(self.globalconfig["DEFAULT"].get("plcgid", 65534)) - th_plc.uid = int(self.globalconfig["DEFAULT"].get("plcuid", 65534)) + th_plc.gid = self.plcgid + th_plc.uid = self.plcuid th_plc.rtlevel = self.rtlevel th_plc.zeroonerror = self.zeroonerror th_plc.zeroonexit = self.zeroonexit @@ -459,12 +492,12 @@ class RevPiPyLoad(): dc["autoreload"] = self.autoreload dc["autostart"] = self.autostart dc["plcworkdir"] = self.plcworkdir - dc["plcprogram"] = self.plcprog + dc["plcprogram"] = self.plcprogram dc["plcarguments"] = self.plcarguments dc["plcslave"] = self.plcslave dc["plcslaveacl"] = self.plcslaveacl.acl dc["plcslaveport"] = self.plcslaveport - dc["pythonversion"] = self.pythonver + dc["pythonversion"] = self.pythonversion dc["rtlevel"] = self.rtlevel dc["xmlrpc"] = self.xmlrpc dc["xmlrpcacl"] = self.xmlrpcacl.acl diff --git a/revpipyload/xrpcserver.py b/revpipyload/xrpcserver.py index f6f6a0d..2320006 100644 --- a/revpipyload/xrpcserver.py +++ b/revpipyload/xrpcserver.py @@ -35,16 +35,52 @@ class SaveXMLRPCServer(SimpleXMLRPCServer): # Klassenvariablen self.aclmgr = ipacl + self.funcacls = {} + self.requestacl = -1 self.tpe = futures.ThreadPoolExecutor(max_workers=1) self.fut = None proginit.logger.debug("leave SaveXMLRPCServer.__init__()") + def _dispatch(self, method, params): + """Prueft ACL Level fuer angeforderte Methode. + + @param method Angeforderte Methode + @param params Argumente fuer Methode + @return Dispatched data + + """ + # ACL Level für angeforderte Methode prüfen + if self.requestacl < self.funcacls.get(method, -1): + raise RuntimeError("function call not allowed") + + # ACL Mode abfragen (Gibt ACL Level als Parameter) + if method == "xmlmodus": + params = (self.requestacl, ) + + return super()._dispatch(method, params) + def isAlive(self): """Prueft ob der XML RPC Server laeuft. @return True, wenn Server noch laeuft""" return False if self.fut is None else self.fut.running() + def register_function(self, acl_level, function, name=None): + """Override register_function to add acl_level. + + @param acl_level ACL level to call this function + @param function Function to register + @param name Alternative name to use + + """ + if type(acl_level) != int: + raise ValueError("parameter acl_level must be ") + + if name is None: + name = function.__name__ + self.funcs[name] = function + self.funcacls[name] = acl_level + def start(self): """Startet den XML-RPC Server.""" proginit.logger.debug("enter SaveXMLRPCServer.start()") @@ -83,15 +119,15 @@ class SaveXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not super().parse_request(): return False - # IP-Adresse prüfen - int_acl = self.server.aclmgr.get_acllevel(self.address_string()) - if int_acl >= 0: + # ACL für IP-Adresse übernehmen + self.server.requestacl = \ + self.server.aclmgr.get_acllevel(self.address_string()) + + if self.server.requestacl >= 0: return True else: self.send_error( - 401, - "IP '{}' not allowed with acl level '{}'" - "".format(self.address_string(), int_acl) + 401, "IP '{}' not allowed".format(self.address_string()) ) return False