| 1 | diff --git a/generate-cert.sh b/generate-cert.sh |
|---|
| 2 | index 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 | + |
|---|
| 13 | diff --git a/manage.py b/manage.py |
|---|
| 14 | old mode 100644 |
|---|
| 15 | new mode 100755 |
|---|
| 16 | diff --git a/pydra_server/cluster/master.py b/pydra_server/cluster/master.py |
|---|
| 17 | index 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 | """ |
|---|
| 86 | diff --git a/pydra_server/cluster/node.py b/pydra_server/cluster/node.py |
|---|
| 87 | index 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) |
|---|