Download

Documentation

Community

Development

Ticket #8: autodiscovery

File autodiscovery, 5.2 KB (added by redduck666, 5 months ago)
Line 
1diff --git a/generate-cert.sh b/generate-cert.sh
2index 4daf76a..ce28e03 100755
3--- a/generate-cert.sh
4+++ b/generate-cert.sh
5@@ -5,4 +5,5 @@ if [ ! -x /usr/bin/certtool ] ; then
6 fi
7 
8 certtool --generate-privkey --outfile ca-key.pem
9-certtool --generate-self-signed --load-privkey ca-key.pem --outfile ca-cert.pem
10\ No newline at end of file
11+certtool --generate-self-signed --load-privkey ca-key.pem --outfile ca-cert.pem
12+
13diff --git a/manage.py b/manage.py
14old mode 100644
15new mode 100755
16diff --git a/pydra_server/cluster/master.py b/pydra_server/cluster/master.py
17index d782e23..59a54c2 100755
18--- a/pydra_server/cluster/master.py
19+++ b/pydra_server/cluster/master.py
20@@ -46,6 +46,12 @@ import datetime
21 
22 from threading import Lock
23 
24+# should be executed before any other reactor stuff to prevent from using non
25+# glib2 event loop which we need for dbus
26+
27+from twisted.internet import glib2reactor
28+glib2reactor.install()
29+
30 from zope.interface import implements
31 from twisted.cred import portal, checkers
32 from twisted.spread import pb
33@@ -56,6 +62,9 @@ from twisted.web import server, resource
34 from twisted.cred import credentials
35 from django.utils import simplejson
36 import settings
37+import dbus, avahi
38+from dbus import DBusException
39+from dbus.mainloop.glib import DBusGMainLoop
40 
41 from pydra_server.models import Node, TaskInstance
42 from pydra_server.cluster.constants import *
43@@ -143,6 +152,42 @@ class Master(object):
44 
45         self.host = 'localhost'
46         self.port = 18800
47+        self.autodiscovery()
48+
49+    def autodiscovery(self, callback=None):
50+        """shamelessly stolen from http://avahi.org/wiki/PythonBrowseExample
51+        """
52+        def service_resolved(*args):
53+            if not  Node.objects.filter(host=args[7], port=args[8]):
54+                node = Node.objects.create(host=args[7], port=args[8])
55+
56+        def print_error(*args):
57+            logger.info("Couldn't resolve avahi name: %s" % args)
58+
59+        def myhandler(interface, protocol, name, stype, domain, flags):
60+
61+            if flags & avahi.LOOKUP_RESULT_LOCAL:
62+                    # local service, skip
63+                    pass
64+
65+            server.ResolveService(interface, protocol, name, stype,
66+                domain, avahi.PROTO_UNSPEC, dbus.UInt32(0),
67+                reply_handler=service_resolved, error_handler=print_error)
68+
69+        loop = DBusGMainLoop()
70+
71+        bus = dbus.SystemBus(mainloop=loop)
72+
73+        server = dbus.Interface( bus.get_object(avahi.DBUS_NAME, '/'),
74+                'org.freedesktop.Avahi.Server')
75+
76+        sbrowser = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
77+                server.ServiceBrowserNew(avahi.IF_UNSPEC,
78+                    avahi.PROTO_UNSPEC, '_pydra._tcp', 'local', dbus.UInt32(0))),
79+                avahi.DBUS_INTERFACE_SERVICE_BROWSER)
80+
81+        sbrowser.connect_to_signal("ItemNew", myhandler)
82+
83 
84     def get_services(self):
85         """
86diff --git a/pydra_server/cluster/node.py b/pydra_server/cluster/node.py
87index fd37c50..f37609b 100755
88--- a/pydra_server/cluster/node.py
89+++ b/pydra_server/cluster/node.py
90@@ -46,6 +46,7 @@ from twisted.application import service, internet
91 
92 import os
93 from subprocess import Popen
94+import platform, dbus, avahi
95 from pydra_server.cluster.auth.rsa_auth import load_crypto
96 from pydra_server.cluster.auth.master_avatar import MasterAvatar
97 
98@@ -55,6 +56,46 @@ import settings
99 from pydra_server.logging.logger import init_logging
100 logger = init_logging(settings.LOG_FILENAME_NODE)
101 
102+class ZeroconfService:
103+    """A simple class to publish a network service with zeroconf using
104+    avahi.
105+
106+    Shamelessly stolen from http://stackp.online.fr/?p=35
107+    """
108+
109+    def __init__(self, name, port, stype="_http._tcp",
110+                 domain="", host="", text=""):
111+        self.name = name
112+        self.stype = stype
113+        self.domain = domain
114+        self.host = host
115+        self.port = port
116+        self.text = text
117+
118+    def publish(self):
119+        bus = dbus.SystemBus()
120+        server = dbus.Interface(
121+                         bus.get_object(
122+                                 avahi.DBUS_NAME,
123+                                 avahi.DBUS_PATH_SERVER),
124+                        avahi.DBUS_INTERFACE_SERVER)
125+
126+        g = dbus.Interface(
127+                    bus.get_object(avahi.DBUS_NAME,
128+                                   server.EntryGroupNew()),
129+                    avahi.DBUS_INTERFACE_ENTRY_GROUP)
130+
131+        g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC,dbus.UInt32(0),
132+                     self.name, self.stype, self.domain, self.host,
133+                     dbus.UInt16(self.port), self.text)
134+
135+        g.Commit()
136+        self.group = g
137+
138+    def unpublish(self):
139+        self.group.Reset()
140+
141+
142 
143 class NodeServer:
144     """
145@@ -80,6 +121,10 @@ class NodeServer:
146 
147         # get information about the server
148         self.determine_info()
149+        service = ZeroconfService(name=platform.node(), port=self.port_base,
150+            stype="_pydra._tcp")
151+        service.publish()
152+
153 
154         logger.info('Node - starting server on port %s' % self.port_base)
155 
156@@ -221,4 +266,4 @@ node_server = NodeServer()
157 
158 # attach service
159 service = node_server.get_service()
160-service.setServiceParent(application)
161\ No newline at end of file
162+service.setServiceParent(application)