signal für neue LogFiles erstellt. FileHandler werden umgehängt

logrotate ruft signal SIGUSR1 auf
Ausgaben des Python PLC Programms über eine PIPE führen um diese in neuen
Loghandler zu schreiben
proginit als globales Modul umgebaut (kein Vererbung mehr)
This commit is contained in:
2017-03-21 18:14:05 +01:00
parent 88ee0e4eae
commit b3c7544daa
7 changed files with 976 additions and 119 deletions

View File

@@ -1,12 +1,4 @@
/var/log/revpipyload
{
rotate 6
weekly
compress
delaycompress
missingok
notifempty
}
/var/log/revpipyloadapp
{
rotate 6
@@ -15,4 +7,7 @@
delaycompress
missingok
notifempty
postrotate
kill -SIGUSR1 `cat /var/run/revpipyload.pid` > /dev/null 2>&1 || true
endscript
}

50
doc/proginit.html Normal file
View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html><head>
<title>proginit</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
proginit</h1>
<p>
Main functions of our program.
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>forked</td></tr><tr><td>globalconffile</td></tr><tr><td>logapp</td></tr><tr><td>logger</td></tr><tr><td>logplc</td></tr><tr><td>pargs</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#cleanup">cleanup</a></td>
<td>Clean up program.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#configure">configure</a></td>
<td>Initialize general program functions.</td>
</tr>
</table>
<hr /><hr />
<a NAME="cleanup" ID="cleanup"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">cleanup</h2>
<b>cleanup</b>(<i></i>)
<p>
Clean up program.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="configure" ID="configure"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">configure</h2>
<b>configure</b>(<i></i>)
<p>
Initialize general program functions.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

699
doc/revpipyload.html Normal file
View File

@@ -0,0 +1,699 @@
<!DOCTYPE html>
<html><head>
<title>revpipyload</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpipyload</h1>
<p>
Revolution Pi Python PLC Loader.
</p><p>
Stellt das RevPiPyLoad Programm bereit. Dieses Programm lauft als Daemon auf
dem Revolution Pi. Es stellt Funktionen bereit, die es ermoeglichen ein Python
Programm zu starten und fuehrt dessen Ausgaben in eine Logdatei. Die Logdaten
koennen am Pi selber oder ueber eine XML-RPC Schnittstelle ausgelesen werden.
</p><p>
Dieser Daemon prueft ob das Python Programm noch lauft und kann es im Fall
eines Absturzes neu starten.
</p><p>
Ueber diesen Daemon kann die gesamte piCtory Konfiguration exportiert oder
importiert, ein Dump vom Prozessabbild gezogen und das eigene Python
Programm hochgeladen werden.
</p><p>
Es kann von dem Python Programm auch eine Archivdatei herunterladen werden,
welche optional auch die piCtory Konfiguraiton beinhaltet. Damit kann man sehr
schnell auf einem Revolution Pi das Programm inkl. piCtory Konfiguration
austauschen.
</p><p>
Die Zugriffsmoeglichkeiten koennen ueber einen Konfigurationsparameter
begrenzt werden!
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>configrsc</td></tr><tr><td>picontrolreset</td></tr><tr><td>procimg</td></tr><tr><td>pyloadverion</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#LogReader">LogReader</a></td>
<td>Ermoeglicht den Zugriff auf die Logdateien.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#PipeLogwriter">PipeLogwriter</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc">RevPiPlc</a></td>
<td>Verwaltet das PLC Python Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad">RevPiPyLoad</a></td>
<td>Hauptklasse, die alle Funktionen zur Verfuegung stellt.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="LogReader" ID="LogReader"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">LogReader</h2>
<p>
Ermoeglicht den Zugriff auf die Logdateien.
</p><p>
Beinhaltet Funktionen fuer den Abruf der gesamten Logdatei fuer das
RevPiPyLoad-System und die Logdatei der PLC-Anwendung.
Ausserdem koennen nur neue Zeilen abgerufen werden, um eine dynamische
Logansicht zu ermoeglichen.
</p><p>
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
None
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#LogReader.__init__">LogReader</a></td>
<td>Instantiiert LogReader-Klasse.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#LogReader.closeall">closeall</a></td>
<td>Fuehrt close auf File Handler durch.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#LogReader.get_applines">get_applines</a></td>
<td>Gibt neue Zeilen ab letzen Aufruf zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#LogReader.get_applog">get_applog</a></td>
<td>Gibt die gesamte Logdatei zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#LogReader.get_plclines">get_plclines</a></td>
<td>Gibt neue Zeilen ab letzen Aufruf zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#LogReader.get_plclog">get_plclog</a></td>
<td>Gibt die gesamte Logdatei zurueck.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="LogReader.__init__" ID="LogReader.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader (Constructor)</h3>
<b>LogReader</b>(<i></i>)
<p>
Instantiiert LogReader-Klasse.
</p><a NAME="LogReader.closeall" ID="LogReader.closeall"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader.closeall</h3>
<b>closeall</b>(<i></i>)
<p>
Fuehrt close auf File Handler durch.
</p><a NAME="LogReader.get_applines" ID="LogReader.get_applines"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader.get_applines</h3>
<b>get_applines</b>(<i></i>)
<p>
Gibt neue Zeilen ab letzen Aufruf zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
list() mit neuen Zeilen
</dd>
</dl><a NAME="LogReader.get_applog" ID="LogReader.get_applog"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader.get_applog</h3>
<b>get_applog</b>(<i></i>)
<p>
Gibt die gesamte Logdatei zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
str() mit Logdaten
</dd>
</dl><a NAME="LogReader.get_plclines" ID="LogReader.get_plclines"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader.get_plclines</h3>
<b>get_plclines</b>(<i></i>)
<p>
Gibt neue Zeilen ab letzen Aufruf zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
list() mit neuen Zeilen
</dd>
</dl><a NAME="LogReader.get_plclog" ID="LogReader.get_plclog"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
LogReader.get_plclog</h3>
<b>get_plclog</b>(<i></i>)
<p>
Gibt die gesamte Logdatei zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
str() mit Logdaten
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="PipeLogwriter" ID="PipeLogwriter"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">PipeLogwriter</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
Thread
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#PipeLogwriter.__init__">PipeLogwriter</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="#PipeLogwriter.run">run</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="#PipeLogwriter.stop">stop</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="PipeLogwriter.__init__" ID="PipeLogwriter.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
PipeLogwriter (Constructor)</h3>
<b>PipeLogwriter</b>(<i>fh</i>)
<a NAME="PipeLogwriter.run" ID="PipeLogwriter.run"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
PipeLogwriter.run</h3>
<b>run</b>(<i></i>)
<a NAME="PipeLogwriter.stop" ID="PipeLogwriter.stop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
PipeLogwriter.stop</h3>
<b>stop</b>(<i></i>)
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="RevPiPlc" ID="RevPiPlc"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiPlc</h2>
<p>
Verwaltet das PLC Python Programm.
</p><p>
Dieser Thread startet das PLC Python Programm und ueberwacht es. Sollte es
abstuerzen kann es automatisch neu gestartet werden. Die Ausgaben des
Programms werden in eine Logdatei umgeleitet, damit der Entwickler sein
Programm analysieren und debuggen kann.
</p><p>
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
Thread
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPlc.__init__">RevPiPlc</a></td>
<td>Instantiiert RevPiPlc-Klasse.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc._configurefh">_configurefh</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc._setuppopen">_setuppopen</a></td>
<td>Setzt UID und GID fuer das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc._spopen">_spopen</a></td>
<td>Startet das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc._zeroprocimg">_zeroprocimg</a></td>
<td>Setzt Prozessabbild auf NULL.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc.newlogfile">newlogfile</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc.run">run</a></td>
<td>Fuehrt PLC-Programm aus und ueberwacht es.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlc.stop">stop</a></td>
<td>Beendet PLC-Programm.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiPlc.__init__" ID="RevPiPlc.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc (Constructor)</h3>
<b>RevPiPlc</b>(<i>program, arguments, pversion</i>)
<p>
Instantiiert RevPiPlc-Klasse.
</p><a NAME="RevPiPlc._configurefh" ID="RevPiPlc._configurefh"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc._configurefh</h3>
<b>_configurefh</b>(<i></i>)
<a NAME="RevPiPlc._setuppopen" ID="RevPiPlc._setuppopen"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc._setuppopen</h3>
<b>_setuppopen</b>(<i></i>)
<p>
Setzt UID und GID fuer das PLC Programm.
</p><a NAME="RevPiPlc._spopen" ID="RevPiPlc._spopen"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc._spopen</h3>
<b>_spopen</b>(<i>lst_proc, filenum=None</i>)
<p>
Startet das PLC Programm.
</p><dl>
<dt><i>lst_proc:</i></dt>
<dd>
Prozessliste
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
subprocess
</dd>
</dl><a NAME="RevPiPlc._zeroprocimg" ID="RevPiPlc._zeroprocimg"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc._zeroprocimg</h3>
<b>_zeroprocimg</b>(<i></i>)
<p>
Setzt Prozessabbild auf NULL.
</p><a NAME="RevPiPlc.newlogfile" ID="RevPiPlc.newlogfile"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc.newlogfile</h3>
<b>newlogfile</b>(<i></i>)
<a NAME="RevPiPlc.run" ID="RevPiPlc.run"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc.run</h3>
<b>run</b>(<i></i>)
<p>
Fuehrt PLC-Programm aus und ueberwacht es.
</p><a NAME="RevPiPlc.stop" ID="RevPiPlc.stop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlc.stop</h3>
<b>stop</b>(<i></i>)
<p>
Beendet PLC-Programm.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="RevPiPyLoad" ID="RevPiPyLoad"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiPyLoad</h2>
<p>
Hauptklasse, die alle Funktionen zur Verfuegung stellt.
</p><p>
Hier wird die gesamte Konfiguraiton eingelesen und der ggf. aktivierte
XML-RPC-Server gestartet.
</p><p>
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
None
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>root</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.__init__">RevPiPyLoad</a></td>
<td>Instantiiert RevPiPyLoad-Klasse.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._loadconfig">_loadconfig</a></td>
<td>Load configuration file and setup modul.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._plcthread">_plcthread</a></td>
<td>Konfiguriert den PLC-Thread fuer die Ausfuehrung.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._sigexit">_sigexit</a></td>
<td>Signal handler to clean and exit program.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._sigloadconfig">_sigloadconfig</a></td>
<td>Signal handler to load configuration.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._signewlogfile">_signewlogfile</a></td>
<td>Signal handler to start new logfile.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.packapp">packapp</a></td>
<td>Erzeugt aus dem PLC-Programm ein TAR-File.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.start">start</a></td>
<td>Start plcload and PLC python program.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.stop">stop</a></td>
<td>Stop PLC python program and plcload.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_getconfig">xml_getconfig</a></td>
<td>Uebertraegt die RevPiPyLoad Konfiguration.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_getfilelist">xml_getfilelist</a></td>
<td>Uebertraegt die Dateiliste vom plcworkdir.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_getpictoryrsc">xml_getpictoryrsc</a></td>
<td>Gibt die config.rsc Datei von piCotry zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_getprocimg">xml_getprocimg</a></td>
<td>Gibt die Rohdaten aus piControl0 zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcdownload">xml_plcdownload</a></td>
<td>Uebertraegt ein Archiv vom plcworkdir.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcexitcode">xml_plcexitcode</a></td>
<td>Gibt den aktuellen exitcode vom PLC Programm zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcrunning">xml_plcrunning</a></td>
<td>Prueft ob das PLC Programm noch lauft.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcstart">xml_plcstart</a></td>
<td>Startet das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcstop">xml_plcstop</a></td>
<td>Stoppt das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcupload">xml_plcupload</a></td>
<td>Empfaengt Dateien fuer das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_plcuploadclean">xml_plcuploadclean</a></td>
<td>Loescht das gesamte plcworkdir Verzeichnis.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_reload">xml_reload</a></td>
<td>Startet RevPiPyLoad neu und verwendet neue Konfiguraiton.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_setconfig">xml_setconfig</a></td>
<td>Empfaengt die RevPiPyLoad Konfiguration.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.xml_setpictoryrsc">xml_setpictoryrsc</a></td>
<td>Schreibt die config.rsc Datei von piCotry.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiPyLoad.__init__" ID="RevPiPyLoad.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad (Constructor)</h3>
<b>RevPiPyLoad</b>(<i></i>)
<p>
Instantiiert RevPiPyLoad-Klasse.
</p><a NAME="RevPiPyLoad._loadconfig" ID="RevPiPyLoad._loadconfig"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._loadconfig</h3>
<b>_loadconfig</b>(<i></i>)
<p>
Load configuration file and setup modul.
</p><a NAME="RevPiPyLoad._plcthread" ID="RevPiPyLoad._plcthread"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._plcthread</h3>
<b>_plcthread</b>(<i></i>)
<p>
Konfiguriert den PLC-Thread fuer die Ausfuehrung.
</p><dl>
<dt>Returns:</dt>
<dd>
PLC-Thread Object or None
</dd>
</dl><a NAME="RevPiPyLoad._sigexit" ID="RevPiPyLoad._sigexit"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._sigexit</h3>
<b>_sigexit</b>(<i>signum, frame</i>)
<p>
Signal handler to clean and exit program.
</p><a NAME="RevPiPyLoad._sigloadconfig" ID="RevPiPyLoad._sigloadconfig"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._sigloadconfig</h3>
<b>_sigloadconfig</b>(<i>signum, frame</i>)
<p>
Signal handler to load configuration.
</p><a NAME="RevPiPyLoad._signewlogfile" ID="RevPiPyLoad._signewlogfile"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._signewlogfile</h3>
<b>_signewlogfile</b>(<i>signum, frame</i>)
<p>
Signal handler to start new logfile.
</p><a NAME="RevPiPyLoad.packapp" ID="RevPiPyLoad.packapp"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.packapp</h3>
<b>packapp</b>(<i>mode="tar", pictory=False</i>)
<p>
Erzeugt aus dem PLC-Programm ein TAR-File.
</p><dl>
<dt><i>mode:</i></dt>
<dd>
Packart 'tar' oder 'zip'
</dd><dt><i>pictory:</i></dt>
<dd>
piCtory Konfiguration mit einpacken
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Dateinamen des Archivs
</dd>
</dl><a NAME="RevPiPyLoad.start" ID="RevPiPyLoad.start"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.start</h3>
<b>start</b>(<i></i>)
<p>
Start plcload and PLC python program.
</p><a NAME="RevPiPyLoad.stop" ID="RevPiPyLoad.stop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.stop</h3>
<b>stop</b>(<i></i>)
<p>
Stop PLC python program and plcload.
</p><a NAME="RevPiPyLoad.xml_getconfig" ID="RevPiPyLoad.xml_getconfig"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_getconfig</h3>
<b>xml_getconfig</b>(<i></i>)
<p>
Uebertraegt die RevPiPyLoad Konfiguration.
</p><dl>
<dt>Returns:</dt>
<dd>
dict() der Konfiguration
</dd>
</dl><a NAME="RevPiPyLoad.xml_getfilelist" ID="RevPiPyLoad.xml_getfilelist"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_getfilelist</h3>
<b>xml_getfilelist</b>(<i></i>)
<p>
Uebertraegt die Dateiliste vom plcworkdir.
</p><dl>
<dt>Returns:</dt>
<dd>
list() mit Dateinamen
</dd>
</dl><a NAME="RevPiPyLoad.xml_getpictoryrsc" ID="RevPiPyLoad.xml_getpictoryrsc"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_getpictoryrsc</h3>
<b>xml_getpictoryrsc</b>(<i></i>)
<p>
Gibt die config.rsc Datei von piCotry zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
xmlrpc.client.Binary()
</dd>
</dl><a NAME="RevPiPyLoad.xml_getprocimg" ID="RevPiPyLoad.xml_getprocimg"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_getprocimg</h3>
<b>xml_getprocimg</b>(<i></i>)
<p>
Gibt die Rohdaten aus piControl0 zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
xmlrpc.client.Binary()
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcdownload" ID="RevPiPyLoad.xml_plcdownload"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcdownload</h3>
<b>xml_plcdownload</b>(<i>mode="tar", pictory=False</i>)
<p>
Uebertraegt ein Archiv vom plcworkdir.
</p><dl>
<dt><i>mode:</i></dt>
<dd>
Archivart 'tar' 'zip'
</dd><dt><i>pictory:</i></dt>
<dd>
piCtory Konfiguraiton mit einpacken
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Binary() mit Archivdatei
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcexitcode" ID="RevPiPyLoad.xml_plcexitcode"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcexitcode</h3>
<b>xml_plcexitcode</b>(<i></i>)
<p>
Gibt den aktuellen exitcode vom PLC Programm zurueck.
</p><dl>
<dt>Returns:</dt>
<dd>
int() exitcode oder:
-1 laeuft noch
-2 Datei nicht gefunden
-3 Lief nie
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcrunning" ID="RevPiPyLoad.xml_plcrunning"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcrunning</h3>
<b>xml_plcrunning</b>(<i></i>)
<p>
Prueft ob das PLC Programm noch lauft.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn das PLC Programm noch lauft
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcstart" ID="RevPiPyLoad.xml_plcstart"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcstart</h3>
<b>xml_plcstart</b>(<i></i>)
<p>
Startet das PLC Programm.
</p><dl>
<dt>Returns:</dt>
<dd>
int() Status:
-1 Programm lauft noch
-2 Datei nicht gefunden
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcstop" ID="RevPiPyLoad.xml_plcstop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcstop</h3>
<b>xml_plcstop</b>(<i></i>)
<p>
Stoppt das PLC Programm.
</p><dl>
<dt>Returns:</dt>
<dd>
int() Exitcode vom PLC Programm
-1 PLC Programm lief nicht
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcupload" ID="RevPiPyLoad.xml_plcupload"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcupload</h3>
<b>xml_plcupload</b>(<i>filedata, filename</i>)
<p>
Empfaengt Dateien fuer das PLC Programm.
</p><dl>
<dt><i>filedata:</i></dt>
<dd>
GZIP Binary data der datei
</dd><dt><i>filename:</i></dt>
<dd>
Name inkl. Unterverzeichnis der Datei
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Ture, wenn Datei erfolgreich gespeichert wurde
</dd>
</dl><a NAME="RevPiPyLoad.xml_plcuploadclean" ID="RevPiPyLoad.xml_plcuploadclean"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_plcuploadclean</h3>
<b>xml_plcuploadclean</b>(<i></i>)
<p>
Loescht das gesamte plcworkdir Verzeichnis.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn erfolgreich
</dd>
</dl><a NAME="RevPiPyLoad.xml_reload" ID="RevPiPyLoad.xml_reload"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_reload</h3>
<b>xml_reload</b>(<i></i>)
<p>
Startet RevPiPyLoad neu und verwendet neue Konfiguraiton.
</p><a NAME="RevPiPyLoad.xml_setconfig" ID="RevPiPyLoad.xml_setconfig"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_setconfig</h3>
<b>xml_setconfig</b>(<i>dc, loadnow=False</i>)
<p>
Empfaengt die RevPiPyLoad Konfiguration.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn erfolgreich angewendet
</dd>
</dl><a NAME="RevPiPyLoad.xml_setpictoryrsc" ID="RevPiPyLoad.xml_setpictoryrsc"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.xml_setpictoryrsc</h3>
<b>xml_setpictoryrsc</b>(<i>filebytes, reset=False</i>)
<p>
Schreibt die config.rsc Datei von piCotry.
</p><dl>
<dt><i>filebytes:</i></dt>
<dd>
xmlrpc.client.Binary()-Objekt
</dd><dt><i>reset:</i></dt>
<dd>
Reset piControl Device
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Statuscode:
0 Alles erfolgreich
-1 Kann JSON-Datei nicht laden
-2 piCtory Elemente in JSON-Datei nicht gefunden
-3 Konnte Konfiguraiton nicht schreiben
Positive Zahl ist exitcode von piControlReset
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpipyload -->
<!-- Saved: 2017-03-20, 15:24:14 -->
<!-- Saved: 2017-03-21, 18:11:09 -->
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
<Project version="5.1">
<Language>en_US</Language>
@@ -9,7 +9,7 @@
<ProgLanguage mixed="0">Python3</ProgLanguage>
<ProjectType>Console</ProjectType>
<Description>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.</Description>
<Version>0.2.9</Version>
<Version>0.2.10</Version>
<Author>Sven Sager</Author>
<Email>akira@narux.de</Email>
<Eol index="-1"/>

View File

@@ -1,29 +1,33 @@
#
# RevPiPyLoad
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
"""Main functions of our program."""
import logging
import sys
from argparse import ArgumentParser
from configparser import ConfigParser
from os import fork as osfork
from os.path import exists as ospexists
forked = False
globalconffile = None
logapp = "revpipyloadapp.log"
logplc = "revpipyload.log"
logger = None
pargs = None
class ProgInit():
"""Programmfunktionen fuer Parameter und Logger."""
def __del__(self):
def cleanup():
"""Clean up program."""
# Logging beenden
logging.shutdown()
def __init__(self):
def configure():
"""Initialize general program functions."""
# Command arguments
@@ -51,23 +55,26 @@ class ProgInit():
pargs = parser.parse_args()
# Prüfen ob als Daemon ausgeführt werden soll
self.pidfile = "/var/run/revpipyload.pid"
self.pid = 0
if pargs.daemon:
global forked
pidfile = "/var/run/revpipyload.pid"
pid = 0
if pargs.daemon and not forked:
# Prüfen ob daemon schon läuft
if ospexists(self.pidfile):
if ospexists(pidfile):
raise SystemError(
"program already running as daemon. check {}".format(
self.pidfile
)
"program already running as daemon. check {}".format(pidfile)
)
self.pid = osfork()
if self.pid > 0:
with open(self.pidfile, "w") as f:
f.write(str(self.pid))
# Zum daemon machen
pid = osfork()
if pid > 0:
with open(pidfile, "w") as f:
f.write(str(pid))
sys.exit(0)
else:
forked = True
if pargs.daemon:
global logapp
global logplc
@@ -79,13 +86,18 @@ class ProgInit():
sys.stderr = sys.stdout
# Initialize configparser globalconfig
self.globalconffile = pargs.conffile
self.globalconfig = ConfigParser()
self.globalconfig.read(pargs.conffile)
global globalconffile
globalconffile = pargs.conffile
# Program logger
global logger
logger = logging.getLogger()
# Alle handler entfernen
for lhandler in logger.handlers:
logger.removeHandler(lhandler)
# Neue Handler bauen
logformat = logging.Formatter(
"{asctime} [{levelname:8}] {message}",
datefmt="%Y-%m-%d %H:%M:%S", style="{"
@@ -93,6 +105,7 @@ class ProgInit():
lhandler = logging.StreamHandler(sys.stdout)
lhandler.setFormatter(logformat)
logger.addHandler(lhandler)
if pargs.logfile is not None:
lhandler = logging.FileHandler(filename=pargs.logfile)
lhandler.setFormatter(logformat)

View File

@@ -39,6 +39,7 @@ import subprocess
import tarfile
import zipfile
from concurrent import futures
from configparser import ConfigParser
from json import loads as jloads
from re import match as rematch
from shutil import rmtree
@@ -51,7 +52,7 @@ from xmlrpc.server import SimpleXMLRPCServer
configrsc = "/opt/KUNBUS/config.rsc"
picontrolreset = "/opt/KUNBUS/piControlReset"
procimg = "/dev/piControl0"
pyloadverion = "0.2.9"
pyloadverion = "0.2.10"
class LogReader():
@@ -72,6 +73,13 @@ class LogReader():
self.fhplc = None
self.posplc = 0
def closeall(self):
"""Fuehrt close auf File Handler durch."""
if self.fhapp is not None:
self.fhapp.close()
if self.fhplc is not None:
self.fhplc.close()
def get_applines(self):
"""Gibt neue Zeilen ab letzen Aufruf zurueck.
@returns: list() mit neuen Zeilen"""
@@ -152,6 +160,39 @@ class LogReader():
return self.fhplc.read()
class PipeLogwriter(Thread):
def __init__(self, fh):
super().__init__()
self._exit = Event()
self.fh = fh
if fh is None:
self.pipeout = None
else:
self._pipein, self.pipeout = os.pipe()
def run(self):
if self.fh is not None:
fhread = os.fdopen(self._pipein)
proginit.logger.debug("enter logreader pipe")
while not self._exit.is_set():
line = fhread.readline()
try:
self.fh.write(line)
self.fh.flush()
except:
pass
proginit.logger.debug("leave logreader pipe")
def stop(self):
proginit.logger.debug("quit pipe logreader")
self._exit.set()
if self.pipeout is not None:
os.write(self.pipeout, b"\n")
os.close(self.pipeout)
os.close(self._pipein)
class RevPiPlc(Thread):
"""Verwaltet das PLC Python Programm.
@@ -170,8 +211,9 @@ class RevPiPlc(Thread):
self._arguments = arguments
self._evt_exit = Event()
self.exitcode = None
self._fh = None
self._fh = self._configurefh()
self.gid = 65534
self.plw = None
self._program = program
self._procplc = None
self._pversion = pversion
@@ -179,21 +221,39 @@ class RevPiPlc(Thread):
self.zeroonerror = False
self.zeroonexit = False
def _configurefh(self):
# Ausgaben konfigurieren und ggf. umleiten
proginit.logger.debug("configure fh applog")
logfile = None
if proginit.pargs.daemon:
if os.access(os.path.dirname(proginit.logapp), os.R_OK | os.W_OK):
logfile = proginit.logapp
elif proginit.pargs.logfile is not None:
logfile = proginit.pargs.logfile
if logfile is not None:
return open(logfile, "a")
else:
return None
def _setuppopen(self):
"""Setzt UID und GID fuer das PLC Programm."""
proginit.logger.debug(
"set uid {} and gid {}".format(self.uid, self.gid))
os.setgid(self.gid)
os.setuid(self.uid)
def _spopen(self, lst_proc):
def _spopen(self, lst_proc, filenum=None):
"""Startet das PLC Programm.
@param lst_proc: Prozessliste
@returns: subprocess"""
proginit.logger.debug("configure subprocess")
return subprocess.Popen(
lst_proc,
preexec_fn=self._setuppopen,
cwd=os.path.dirname(self._program),
bufsize=1,
stdout=subprocess.STDOUT if self._fh is None else self._fh,
stdout=subprocess.STDOUT if filenum is None else filenum,
stderr=subprocess.STDOUT
)
@@ -203,6 +263,20 @@ class RevPiPlc(Thread):
f = open("/dev/piControl0", "w+b", 0)
f.write(bytes(4096))
def newlogfile(self):
if self._fh is not None:
self._fh.close()
self._fh = self._configurefh()
if self.plw is not None:
self.plw.fh = self._fh
self._fh.write("-" * 55)
self._fh.write("\nstart new logfile: {}\n".format(asctime()))
self._fh.flush()
proginit.logger.info("new plc logfile")
def run(self):
"""Fuehrt PLC-Programm aus und ueberwacht es."""
if self._pversion == 2:
@@ -214,25 +288,21 @@ class RevPiPlc(Thread):
self._program, self._arguments
))
# Ausgaben konfigurieren und ggf. umleiten
logfile = None
if proginit.pargs.daemon:
if os.access(os.path.dirname(proginit.logapp), os.R_OK | os.W_OK):
logfile = proginit.logapp
elif proginit.pargs.logfile is not None:
logfile = proginit.pargs.logfile
if logfile is not None:
self._fh = open(logfile, "a")
# Logausgabe
if self._fh is not None:
self._fh.write("-" * 55)
self._fh.write("\nplc: {} started: {}\n".format(
os.path.basename(self._program), asctime()
))
self._fh.flush()
# LogWriter
self.plw = PipeLogwriter(self._fh)
self.plw.start()
# Prozess erstellen
proginit.logger.info("start plc program {}".format(self._program))
self._procplc = self._spopen(lst_proc)
self._procplc = self._spopen(lst_proc, self.plw.pipeout)
while not self._evt_exit.is_set():
@@ -263,7 +333,7 @@ class RevPiPlc(Thread):
if not self._evt_exit.is_set() and self.autoreload:
# Prozess neu starten
self._procplc = self._spopen(lst_proc)
self._procplc = self._spopen(lst_proc, self.plw.pipeout)
if self.exitcode == 0:
proginit.logger.warning(
"restart plc program after clean exit"
@@ -277,8 +347,15 @@ class RevPiPlc(Thread):
self._evt_exit.wait(1)
def stop(self):
"""Beendet PLC-Programm."""
proginit.logger.info("stop revpiplc thread")
self._evt_exit.set()
# Prüfen ob es einen subprocess gibt
if self._procplc is None:
if self.plw is not None:
self.plw.stop()
return
# Prozess beenden
@@ -305,12 +382,11 @@ class RevPiPlc(Thread):
or self.zeroonerror and self.exitcode != 0:
self._zeroprocimg()
def stop(self):
"""Beendet PLC-Programm."""
self._evt_exit.set()
if self.plw is not None:
self.plw.stop()
class RevPiPyLoad(proginit.ProgInit):
class RevPiPyLoad():
"""Hauptklasse, die alle Funktionen zur Verfuegung stellt.
@@ -321,10 +397,11 @@ class RevPiPyLoad(proginit.ProgInit):
def __init__(self):
"""Instantiiert RevPiPyLoad-Klasse."""
super().__init__()
proginit.configure()
self._exit = True
self.evt_loadconfig = Event()
self.globalconfig = ConfigParser()
self.logr = LogReader()
self.plc = None
self.tfile = {}
@@ -338,6 +415,7 @@ class RevPiPyLoad(proginit.ProgInit):
signal.signal(signal.SIGINT, self._sigexit)
signal.signal(signal.SIGTERM, self._sigexit)
signal.signal(signal.SIGHUP, self._sigloadconfig)
signal.signal(signal.SIGUSR1, self._signewlogfile)
def _loadconfig(self):
"""Load configuration file and setup modul."""
@@ -353,9 +431,9 @@ class RevPiPyLoad(proginit.ProgInit):
# Konfigurationsdatei laden
proginit.logger.info(
"loading config file: {}".format(self.globalconffile)
"loading config file: {}".format(proginit.globalconffile)
)
self.globalconfig.read(self.globalconffile)
self.globalconfig.read(proginit.globalconffile)
# Konfiguration verarbeiten
self.autoreload = \
@@ -473,11 +551,29 @@ class RevPiPyLoad(proginit.ProgInit):
proginit.logger.debug("got exit signal")
self.stop()
# Programm aufräumen
proginit.cleanup()
def _sigloadconfig(self, signum, frame):
"""Signal handler to load configuration."""
proginit.logger.debug("got reload config signal")
self.evt_loadconfig.set()
def _signewlogfile(self, signum, frame):
"""Signal handler to start new logfile."""
proginit.logger.debug("got new logfile signal")
# Logger neu konfigurieren
proginit.configure()
proginit.logger.info("start new logfile: {}".format(asctime()))
# stdout für revpipyplc
if self.plc is not None:
self.plc.newlogfile()
# Logreader schließen
self.logr.closeall()
def packapp(self, mode="tar", pictory=False):
"""Erzeugt aus dem PLC-Programm ein TAR-File.
@@ -673,9 +769,13 @@ class RevPiPyLoad(proginit.ProgInit):
def xml_plcstop(self):
"""Stoppt das PLC Programm.
@returns: int() Exitcode vom PLC Programm"""
@returns: int() Exitcode vom PLC Programm
-1 PLC Programm lief nicht
"""
proginit.logger.debug("xmlrpc call plcstop")
if self.plc is not None:
if self.plc is not None and self.plc.is_alive():
self.plc.stop()
self.plc.join()
return self.plc.exitcode
@@ -760,10 +860,10 @@ class RevPiPyLoad(proginit.ProgInit):
self.globalconfig.set("DEFAULT", key, str(dc[key]))
# conf-Datei schreiben
fh = open(self.globalconffile, "w")
fh = open(proginit.globalconffile, "w")
self.globalconfig.write(fh)
proginit.logger.info(
"got new config and wrote it to {}".format(self.globalconffile)
"got new config and wrote it to {}".format(proginit.globalconffile)
)
if loadnow:

View File

@@ -27,7 +27,7 @@ setup(
license="LGPLv3",
name="revpipyload",
version="0.2.9",
version="0.2.10",
scripts=["data/revpipyload"],