IpAclManager.loadacl hinzugefügt

IpAclManager.valid_acl_string entfernt
SaveXMLRPCServer übernimmt ACL Level bei Funktionsregistrierung
SaveXMLRPCServer _dispatch werte ACL Level der Methode aus
Konfigdatei mit neuen Sektionen PLCSLAVE und XMLRPC versehen
Parameter autoreloaddelay für PLC-Neustart integriert
ACL Vergabe für alle register_function Aufrufe
This commit is contained in:
2018-03-12 10:56:06 +01:00
parent f34227fa6e
commit fe05ccdc54
8 changed files with 242 additions and 116 deletions

View File

@@ -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 = *

View File

@@ -74,8 +74,8 @@ Methods</h3>
<td><a style="color:#0000FF" href="#IpAclManager.get_acllevel">get_acllevel</a></td>
<td>Prueft IP gegen ACL List und gibt ACL-Wert aus.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#IpAclManager.valid_acl_string">valid_acl_string</a></td>
<td>Prueft ob ein ACL-String gueltig ist.</td>
<td><a style="color:#0000FF" href="#IpAclManager.loadacl">loadacl</a></td>
<td>Laed ACL String und gibt erfolg zurueck.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
@@ -135,17 +135,21 @@ zum pruefen
<dd>
<class 'int'> ACL Wert oder -1 wenn nicht gefunden
</dd>
</dl><a NAME="IpAclManager.valid_acl_string" ID="IpAclManager.valid_acl_string"></a>
</dl><a NAME="IpAclManager.loadacl" ID="IpAclManager.loadacl"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
IpAclManager.valid_acl_string</h3>
<b>valid_acl_string</b>(<i>str_acl</i>)
IpAclManager.loadacl</h3>
<b>loadacl</b>(<i>str_acl</i>)
<p>
Prueft ob ein ACL-String gueltig ist.
Laed ACL String und gibt erfolg zurueck.
</p><dl>
<dt><i>str_acl</i></dt>
<dd>
<class 'str'> zum ueberpruefen
return ACL Level als <class 'int'>
ACL als <class 'str'>
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
True, wenn erfolgreich uebernommen
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>

View File

@@ -101,9 +101,15 @@ Methods</h3>
<td><a style="color:#0000FF" href="#SaveXMLRPCServer.__init__">SaveXMLRPCServer</a></td>
<td>Init SaveXMLRPCServer class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#SaveXMLRPCServer._dispatch">_dispatch</a></td>
<td>Prueft ACL Level fuer angeforderte Methode.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#SaveXMLRPCServer.isAlive">isAlive</a></td>
<td>Prueft ob der XML RPC Server laeuft.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#SaveXMLRPCServer.register_function">register_function</a></td>
<td>Override register_function to add acl_level.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#SaveXMLRPCServer.start">start</a></td>
<td>Startet den XML-RPC Server.</td>
</tr><tr>
@@ -122,7 +128,26 @@ SaveXMLRPCServer (Constructor)</h3>
<b>SaveXMLRPCServer</b>(<i>addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=IpAclManager()</i>)
<p>
Init SaveXMLRPCServer class.
</p><a NAME="SaveXMLRPCServer.isAlive" ID="SaveXMLRPCServer.isAlive"></a>
</p><a NAME="SaveXMLRPCServer._dispatch" ID="SaveXMLRPCServer._dispatch"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
SaveXMLRPCServer._dispatch</h3>
<b>_dispatch</b>(<i>method, params</i>)
<p>
Prueft ACL Level fuer angeforderte Methode.
</p><dl>
<dt><i>method</i></dt>
<dd>
Angeforderte Methode
</dd><dt><i>params</i></dt>
<dd>
Argumente fuer Methode
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Dispatched data
</dd>
</dl><a NAME="SaveXMLRPCServer.isAlive" ID="SaveXMLRPCServer.isAlive"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
SaveXMLRPCServer.isAlive</h3>
<b>isAlive</b>(<i></i>)
@@ -133,6 +158,23 @@ Prueft ob der XML RPC Server laeuft.
<dd>
True, wenn Server noch laeuft
</dd>
</dl><a NAME="SaveXMLRPCServer.register_function" ID="SaveXMLRPCServer.register_function"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
SaveXMLRPCServer.register_function</h3>
<b>register_function</b>(<i>acl_level, function, name=None</i>)
<p>
Override register_function to add acl_level.
</p><dl>
<dt><i>acl_level</i></dt>
<dd>
ACL level to call this function
</dd><dt><i>function</i></dt>
<dd>
Function to register
</dd><dt><i>name</i></dt>
<dd>
Alternative name to use
</dd>
</dl><a NAME="SaveXMLRPCServer.start" ID="SaveXMLRPCServer.start"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
SaveXMLRPCServer.start</h3>

View File

@@ -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())

View File

@@ -50,7 +50,7 @@ class IpAclManager():
if type(value) != str:
raise ValueError("parameter acl must be <class 'str'>")
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 <class 'str'> zum ueberpruefen
return ACL Level als <class 'int'>"""
return refullmatch(self.__re_ipacl, str_acl)
def loadacl(self, str_acl):
"""Laed ACL String und gibt erfolg zurueck.
@param str_acl ACL als <class 'str'>
@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)

View File

@@ -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()")

View File

@@ -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

View File

@@ -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 <class 'int'>")
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