Python Skript funktioniert im Terminal, aber nicht über Apache

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
luckystriker
User
Beiträge: 6
Registriert: Dienstag 23. Mai 2017, 14:17

Hallo Zusammen,

ich schreibe momentan ein Python-Skript, dass über eine Webseite aufgerufen werden soll. Dieses Skript hat dann die Aufgabe, einen OPSI-Client zu erstellen (Open PC Server Integration - ein Server zum Rollout von Software und zur Inventarisierung von Rechnern). Dieser Opsi-Server ist ebenfalls in Python geschrieben, und so existiert ein eigenes Package namens "opsi", welches einen Befehl mitbringt, um per Shell einen Client auch manuell anzulegen.

Nachdem ich nun bereits über einige Steine gestolpert bin, komme ich mit folgendem Problem nicht nach: Sofern ich im Terminal selber über

Code: Alles auswählen

python script.py
mein Skript aufrufe, funktioniert alles wunderbar. Die Clients werden wie gewünscht angelegt, Ausgaben werden wie gewollt und Default auf der Console ausgegeben.

Nun habe ich dieses Skript in Apache eingebettet, und möchte es über eine Webseite
ausführen.
Es wird auch ausgeführt, jedoch werden sämtliche Befehle die einen Systemaufruf antriggern einfach "überfahren", und "funktionieren nicht". Print-Ausgaben zum Beispiel funktionieren wie gewohnt.

Was ich bereits probiert habe:

Code: Alles auswählen

os.system("opsi-admin -rd method createClient ....)"
ein

Code: Alles auswählen

print(os.system("opsi-admin -rd method createClient ...."))
liefert die Ausgabe des Return-Codes, damit man überhaupt etwas sieht.
Ergebnis:
Der Return-Code ist 256 (also nach dem 16bit-Schema: 1), also scheint es irgendwo Probleme zu geben. Der Error-Log von Apache ist diesbezüglich leer, der Client wird nicht angelegt.


Dann habe ich probiert, über einen subprocess den Client zu erstellen:

Code: Alles auswählen

subprocess.Popen(["/usr/bin/opsi-admin", "-d", "method", "createClient",  ....])
und auch

Code: Alles auswählen

subprocess.call(["/usr/bin/opsi-admin", "-d", "method", "createClient",  ....])
Ergebnis:
Komplette Print-Ausgabe des Skripts, augenscheinlich alles gut, Client ist trotzdem nicht erstellt worden. Keine Fehlermeldungen im Apache.log.


Dann habe ich noch eine andere opsi-seitige Möglichkeit probiert, und zwar über ein Backend, hier ein copy-paste aus dem OPSI-Forum:

Code: Alles auswählen

backend = BackendManager(
        dispatchConfigFile=u'/etc/opsi/backendManager/dispatch.conf',
        backendConfigDir=u'/etc/opsi/backends',
        extensionConfigDir=u'/etc/opsi/backendManager/extend.d'
)
# Ab python-opsi 4.0.6.39 geht es dann sogar so:
# backend = BackendManager()

# Direkter Weg ohne Backend-Erweiterung:
backend.host_createOpsiClient(id='client{0}.uib.local'.format(someID), ipAddress=theIP, hardwareAddress=theMAC)

# Über die Erweiterung wäre es dann:
# backend.createClient("client" + str(someID), 'uib.local', ipAddress=theIP, hardwareAddress=theMAC)
Alle hier gezeigten Wege habe ich probiert.
Ergebnis:
Traceback (most recent call last):
File "/usr/lib/cgi-bin/script.py", line 123, in <module>
backend = BackendManager(dispatchConfigFile=u'/etc/opsi/backendManager/dispatch.conf', backendConfigDir=u'/etc/opsi/backends',
extensionConfigDir=u'/etc/opsi/backendManager/extend.d')
File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 256, in __init__
self._backend = BackendDispatcher(context=self, **kwargs)
File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 372, in __init__
self.__loadDispatchConfig()
File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 404, in __loadDispatchConfig
raise BackendConfigurationError: <BackendConfigurationError(u"Dispatch config file '/etc/opsi/backendManager/dispatch.conf' not found")>
Die Datei /etc/opsi/backendManager/dispatch.conf ist aber an jenem Ort aufzufinden...

Es scheint, als habe er generell Probleme mit Systemaufrufen. Also nicht nur im Kontext dieses einen Zwecks, einen neuen Client anzulegen. Das lässt in mir die Ahnung reifen, dass das Problem etwas mit dem Apache und dem Skript bzw. Zugriff des Skripts selber zutun haben könnte.
Es wird nicht gemeckert, und es scheint als würde alles ausgeführt werden, aber das Ergebnis ist nicht wie erwartet.
So funktioniert zum Beispiel auch ein einfaches

Code: Alles auswählen

os.system("opsi-convert file mysql")
nicht. (Der Befehl synchronisiert bzw. konvertiert den Inhalt des File-Backends in das MySQL-Backend des Opsis.) Im Terminal selber habe ich ein komplett lauffähiges Skript.

Das Skript selbst hat die Berechtigung "-rwxr-xr-x" über

Code: Alles auswählen

chmod 0755 /usr/lib/cgi-bin/script.py
, sollte also daran auch nicht liegen..

Kann mir jemand helfen? Ich habe echt keine Ahnung mehr wo ich suchen soll. :(

Viele Grüße und Danke im Voraus,
Lucky
BlackJack

@luckystriker: Von `os.system()` solltest Du die Finger lassen. Wenn schon dann `subprocess`, und sowohl `stdout` als auch `stderr` umleiten und dann am einfachsten mit der `communicate()`-Methode abgreifen. Danach dann einfach mal alles ausgeben: die Rückgabe von `communicate()` und den Rückgabecode vom Prozess abfragen und ausgeben. Dann solltest Du sehen was an Fehlermeldungen ausgegeben wird.

Ich würde ja mal auf Rechteprobleme tippen. Eventuell sogar ein chroot für den Webserver wenn die Konfigurationsdateien in ``/etc/`` nicht gefunden werden können‽ Alternativ kannst Du ja mal versuchen Dein Programm manuell mit den Rechten vom Webserver auszuführen.
luckystriker
User
Beiträge: 6
Registriert: Dienstag 23. Mai 2017, 14:17

Hi BlackJack,

danke für deine Antwort. Kannst du mir sagen wie ich das über den Webserver-Aufruf verwirklichen kann? Habe die Ausgabe mal umgeleitet in eine Text-Datei, im Falle von stdout ist die Ausgabe die ganz normale Terminal-Ausgabe (im Terminal funktioniert ja auch alles), im Falle von stderr ist die Datei leer.
Ich hab jetzt schon ein wenig recherchiert, aber weiß nicht, wie ich die communicate-Funktion genau einsetze, bzw. wie ich es schaffe, dass der Aufruf durch den Webserver in eine Datei umgeleitet wird... ich rufe das Skript ja direkt über die URL auf.

Viele Grüße
Lucky :)
BlackJack

@luckystriker: Nicht in eine Datei — an Dein Programm, damit Du das dann dem Benutzer im Browser anzeigen kannst.
luckystriker
User
Beiträge: 6
Registriert: Dienstag 23. Mai 2017, 14:17

Ich frage so etwas ungerne, aber kannst du mir vielleicht bzgl. der Implementierung helfen, vllt mit ein paar Code-Schnipseln? Ich kriege es leider nicht hin, die Ausgabe korrekt umzuleiten bzw. die communicate-Funktion zu nutzen. Das ist auch mein erstes richtiges Projekt in Python.. bin noch Student...

Das wäre sehr nett.

Viele Grüße
Lucky
luckystriker
User
Beiträge: 6
Registriert: Dienstag 23. Mai 2017, 14:17

Ich habe jetzt in der Zwischenzeit mal das Skript mit den Rechten des Webservers ausgeführt, und

Code: Alles auswählen

subprocess.Popen(["opsi-admin", "-d", "method", "createClient", ....], stderr=subprocess.STDOUT)

eingefügt. Das Ergebnis ist das Gleiche wie im Webbrowser, es scheint problemlos durchzulaufen, jedoch wird kein Client erstellt und es wird mir nachdem mein Skript abgearbeitet ist (trotz Auskommentierung des Befehls zum Anlegen eines Clients über die mitgelieferte Backend-Lösung) eine Fehlermeldung ausgegeben, welche sich auf eine angebliche Fehl-konfiguration des Backends bezieht, obwohl ich das Backend nicht benutze.
Client(s) erfolgreich angelegt! Bitte starten Sie den Rechner neu um den PXE-Boot zu starten. <Hier ist das Ende meines Skripts>
<Jetzt geht es hier weiter mit der Fehlermeldung>
root@opsiserver:/usr/lib/cgi-bin# [2] Traceback: (Logger.py | 753)
[2] File "/usr/lib/opsi-admin", line 1675, in <module> main(sys.argv[1:])
(Logger.py | 753)
[2] File "/usr/bin/opsi-admin", line 243, in main
hostControlSafeBackend=True
[2] File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 256, in __init__
self._backend = BackendDispatcher(context=self, **kwargs)
(Logger.py | 753)
[2] File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 372, in __init__
self.__loadDispatchConfig()
(Logger.py | 753)
[2] File "/usr/lib/python2.7/dist-packages/OPSI/Backend/BackendManager.py", line 404, in __loadDispatchConfig__
raise BackendConfigurationError(u"Dispatch config file '%s' not found" % self._dispatchConfigFile)
(Logger.py | 753)
[2] ==>>> Backend configuration error: Dispatch config file '/etc/opsi/backendManager/dispatch.conf' not found (opsi-admin|1682)
[3] Error during execution: Backend configuration error: Dispatch config file '/etc/opsi/backendManager/dispatch.conf' not found (opsi-admin|1683)
<hier wartet er auf eine weitere Eingabe, so dass ich mit STRG+C abbrechen muss, um wieder zur Kommandozeile "zurückzukehren"
Dann wäre es ja naheliegend (da er das Backend nicht anfasst), dass wirklich irgendwelche Rechte nicht stimmen und er die Dateien deshalb nicht finden kann... :(
Antworten