Webbasierter Remotedesktop mit Guacamole und Django

Guacamole 3 3

Als Teil eines neuen Neu skalieren Am Hackday wollte ich eine Remotedesktop-Funktionalität im Browser für die Knoten integrieren, die im Namen des Benutzers gestartet werden. Die meisten an Rescale übermittelten Workflows sind Stapelverarbeitungsaufträge, die unbeaufsichtigt ausgeführt werden. Die Möglichkeit, sich an einem Computer anzumelden und eine GUI zur Überwachung der laufenden Simulation auszuführen, kann für einige Benutzer jedoch nützlich sein.

Eine schnelle Google-Suche ergab eine Bibliothek namens Guacamole das es nun schon seit einigen Jahren gibt. Guacamole besteht aus drei Hauptkomponenten: einer Daemon-Anwendung namens guacd, die zwischen verschiedenen Remote-Desktop-Protokollen (VNC, RDC, SSH) und einem benutzerdefinierten Guacamole-Protokoll übersetzt, einer Reihe von Javascript-Bibliotheken, die den Remote-Desktop in ein HTML5-Canvas-Element rendern und auf Maus- und Tastaturereignisse warten, und schließlich einer schlanken Webanwendung, die HTTP-Anfragen von den JS-Bibliotheken empfängt und mit dem guacd-Daemon(*) kommuniziert.

Leider gibt es eine gewisse Diskrepanz zwischen der bereitgestellten Webanwendung, einem Java-Servlet, und unserem bestehenden Django-Web-Stack. Es wäre viel einfacher, Guacamole in unser bestehendes Produkt zu integrieren, wenn es eine Python-Version der Webanwendung gäbe. Glücklicherweise ist die docs Geben Sie an, dass dies relativ einfach sein sollte. Der Quellcode ist gut geschrieben und es war ziemlich einfach, schnell eine Version in Hackday-Qualität auf Python zu portieren.

Die Guacamole-JS-Bibliotheken starten mit einer Verbindungsanfrage an die Web-App. Dabei wird ein Socket zu Guacd geöffnet und ihm eine Tunnel-ID zugewiesen, die dann an den Client zurückgegeben wird. Wichtig ist hierbei, dass dieser Socket von mehreren HTTP-Anfragen mit derselben Tunnel-ID gemeinsam genutzt werden muss. Um dies sicher zu gewährleisten, wird ein Sperrpaar verwendet, um sicherzustellen, dass immer nur ein Thread vom Socket liest oder in den Socket schreibt. Der folgende Codeausschnitt zeigt, wie Guacd-Anweisungen über eine Django-View-Hilfsfunktion an den Client zurückgegeben werden:

sockets = {} sockets_lock = threading.RLock() read_lock = threading.RLock() write_lock = threading.RLock() pending_read_request = threading.Event() def _do_read(request, cache_key): pending_read_request.set() def content(): mit sockets_lock: guac = sockets[cache_key] mit read_lock: pending_read_request.clear() while True: content = guac.read() if content: yield content sonst: break if pending_read_request.is_set(): logger.info('Übernahme durch eine andere Anfrage.') break # Ende-der-Anweisung-Markierung yield '0.;' response = StreamingHttpResponse( content(), content_type='application/octet-stream') response['Cache-Control'] = 'no-cache' return response

Ein interessanter Aspekt ist, dass die Guacamole-JS-Bibliotheken streamt Daten vom Server mithilfe eines abwechselnden Paars von AJAX-Anfragen. Zunächst wird eine erste AJAX-Anfrage gestellt. Nachdem diese erste Verbindung hergestellt ist und Daten vom Server zurückfließen, wird ein zweiter Verbindungsversuch unternommen. Die Webanwendung muss dies serverseitig erkennen, die erste Verbindung beenden und dann über die zweite Verbindung mit der Datenübertragung beginnen können. Der im Java-Code verwendete ReentrantLock erkennt auf einfache Weise, ob andere Threads warten, der Python-RLock bietet jedoch keine ähnliche Methode. Ein Ereignis wird als schneller und einfacher Signalmechanismus zwischen den beiden laufenden HTTP-Anfragen verwendet.
Offensichtlich wurde dies so schnell wie möglich gehackt und ist nicht für den produktiven Einsatz geeignet. Es enthält wahrscheinlich mehrere Fehler. Eine der größten Einschränkungen besteht derzeit darin, dass die mit guacd verbundenen Sockets derzeit einfach in einem gemeinsamen, globalen Wörterbuch gespeichert sind. Daher ist dies nur für einen HTTP-Server geeignet, der als einzelner Prozess mit mehreren Threads zur Bearbeitung der Anfragen ausgeführt wird.

Insgesamt war es ein unterhaltsames kleines Stück Code, das portiert werden konnte. Ein großes Lob an die Guacamole-Autoren für ihre harte Arbeit. Ein Beispielprojekt für Django/Guacamole ist verfügbar auf github für die Neugierigen.

(*) Guacamole unterstützt zwar WebSockets, doch der standardmäßig verwendete HTTP-Tunneling-Ansatz ist bei der Unterstützung älterer Browser von Vorteil. Trotz der verschiedenen Shims zur Emulation moderner Browser gilt: Je weniger Abhängigkeiten von HTML5-Funktionen bestehen, desto besser ist die Kompatibilität mit älteren Browsern.