398 lines
16 KiB
Python
Executable File
398 lines
16 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: iso-8859-15 -*-
|
|
|
|
|
|
# Glasnost
|
|
# By: Odile Bénassy <obenassy@entrouvert.com>
|
|
# Romain Chantereau <rchantereau@entrouvert.com>
|
|
# Nicolas Clapiès <nclapies@easter-eggs.org>
|
|
# Pierre-Antoine Dejace <padejace@entrouvert.be>
|
|
# Thierry Dulieu <tdulieu@easter-eggs.com>
|
|
# Florent Monnier <monnier@codelutin.com>
|
|
# Cédric Musso <cmusso@easter-eggs.org>
|
|
# Frédéric Péters <fpeters@entrouvert.be>
|
|
# Benjamin Poussin <poussin@codelutin.com>
|
|
# Emmanuel Raviart <eraviart@entrouvert.com>
|
|
# Sébastien Régnier <regnier@codelutin.com>
|
|
# Emmanuel Saracco <esaracco@easter-eggs.com>
|
|
#
|
|
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
|
|
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
|
|
# Emmanuel Saracco & Théridion
|
|
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
|
|
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
|
|
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
|
|
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
|
|
# Régnier, Emmanuel Saracco, Théridion & Vecam
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
__doc__ = """Glasnost Dispatcher"""
|
|
|
|
__version__ = '$Revision$'[11:-2]
|
|
|
|
|
|
import sys
|
|
import whrandom
|
|
|
|
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
|
|
sys.path.insert(0, glasnostPythonDir)
|
|
|
|
import glasnost
|
|
|
|
import glasnost.common.faults as faults
|
|
import glasnost.common.tools_new as commonTools
|
|
|
|
from glasnost.server.ObjectsServer import Server, VirtualServer
|
|
from glasnost.server.tools import *
|
|
|
|
from glasnost.proxy.DispatcherProxy import callServer, getApplicationToken
|
|
|
|
|
|
applicationName = 'Dispatcher'
|
|
applicationRole = None
|
|
|
|
|
|
class DispatcherVirtualServer(VirtualServer):
|
|
"""Partial class designed for aggregation.
|
|
|
|
The aggregation of this class in the Dispatcher is used in order to provide
|
|
special virtual server, a dispatcher virtual server.
|
|
|
|
Attributes:
|
|
===========
|
|
|
|
*applicationTokens*:
|
|
The dictionnary containing all the Glasnost application token. The
|
|
key is the client token.
|
|
|
|
*serverAccessors*:
|
|
The servers access informations dictionnary, sorted by applicationId.
|
|
It consists of:
|
|
|
|
serverHostName:
|
|
The server IP adress or hostname.
|
|
|
|
serverPort:
|
|
The port where request will be sent.
|
|
|
|
isGateway:
|
|
If true (or 1), the request are sent through the Glasnost gateway.
|
|
|
|
*serverInfos*:
|
|
The role and accessor of each server, sorted by "hostName:port".
|
|
|
|
*virtualServerIds*:
|
|
The dictionnary containing all the Glasnost servers ID string
|
|
(including virtual servers) registered to this Dispatcher instance. The
|
|
key is the application Token, the value is the virtual server ID
|
|
string.
|
|
|
|
"""
|
|
|
|
applicationTokens = None
|
|
dispatcherIds = None
|
|
serverAccessors = None
|
|
defaultAccessors = None
|
|
serverInfos = None
|
|
virtualServerIds = None
|
|
|
|
def init(self):
|
|
VirtualServer.init(self)
|
|
self.applicationTokens = {}
|
|
self.defaultAccessors = {}
|
|
self.dispatcherIds = ['glasnost://system']
|
|
self.serverAccessors = {}
|
|
self.serverInfos = {}
|
|
self.virtualServerIds = {}
|
|
|
|
|
|
class Dispatcher(Server):
|
|
VirtualServer = DispatcherVirtualServer
|
|
hasMultipleVirtualServers = 0
|
|
randomGenerator = None
|
|
useDataFile = 0
|
|
|
|
def getApplicationId(self, applicationToken):
|
|
"""Get the application ID from the application token.
|
|
|
|
Keyword arguments:
|
|
==================
|
|
|
|
*applicationToken*:
|
|
The valid application token.
|
|
|
|
Return the application ID string.
|
|
|
|
Exception:
|
|
==========
|
|
|
|
*faults.UnknownApplicationToken*:
|
|
The given application token is not in the dispatcher virtual server
|
|
ids dictionnary.
|
|
|
|
"""
|
|
|
|
virtualServer = self.getVirtualServer(None)
|
|
if not virtualServer.virtualServerIds.has_key(applicationToken):
|
|
raise faults.UnknownApplicationToken(applicationToken)
|
|
return virtualServer.virtualServerIds[applicationToken]
|
|
|
|
def getApplicationToken(self, clientId):
|
|
virtualServer = self.getVirtualServer(None)
|
|
virtualServer.lock.acquire()
|
|
if virtualServer.applicationTokens.has_key(clientId):
|
|
clientToken = virtualServer.applicationTokens[clientId]
|
|
virtualServer.lock.release()
|
|
else:
|
|
while 1:
|
|
clientToken = str(self.randomGenerator.uniform(0.1, 1))[2:]
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
break
|
|
virtualServer.applicationTokens[clientId] = clientToken
|
|
virtualServer.virtualServerIds[clientToken] = clientId
|
|
virtualServer.lock.release()
|
|
virtualServer.markCoreAsDirty()
|
|
return clientToken
|
|
|
|
def getRegisteredRoles(self):
|
|
virtualServer = self.getVirtualServer(None)
|
|
dispatcherId = context.getVar('applicationId')
|
|
# Note: in the next lines, the dispatcher role ('') is removed from the
|
|
# list of roles.
|
|
if virtualServer.serverAccessors.has_key(dispatcherId):
|
|
return [serverInfo['role']
|
|
for serverInfo in virtualServer.serverInfos.values()
|
|
if virtualServer.serverAccessors.has_key(
|
|
commonTools.makeApplicationId(
|
|
dispatcherId, serverInfo['role'])) \
|
|
and serverInfo['role']]
|
|
else:
|
|
# Use the roles of the default accessors.
|
|
return [serverInfo['role']
|
|
for serverInfo in virtualServer.serverInfos.values()
|
|
if serverInfo['role']]
|
|
|
|
def getServerAccessor(self, serverId):
|
|
"""Return the server access information dictionnary.
|
|
|
|
|
|
Keyword argument:
|
|
=================
|
|
|
|
*serverId*:
|
|
The server ID string to access to.
|
|
|
|
Return the server access information dictionnary.
|
|
|
|
*Exceptions*:
|
|
=============
|
|
|
|
*faults.UnknownServerId*:
|
|
The server ID does not exists in the server dictionnary of server
|
|
access informations dictionnary.
|
|
|
|
"""
|
|
|
|
virtualServer = self.getVirtualServer(None)
|
|
if not virtualServer.serverAccessors.has_key(serverId):
|
|
serverDispatcherId = commonTools.extractDispatcherId(serverId)
|
|
if serverDispatcherId != context.getVar('dispatcherId'):
|
|
raise faults.UnknownDispatcherInId(serverId)
|
|
serverRole = commonTools.extractRole(serverId)
|
|
if not virtualServer.defaultAccessors.has_key(serverRole):
|
|
raise faults.UnknownServerId(serverId)
|
|
serverAccessor = virtualServer.defaultAccessors[serverRole]
|
|
if serverDispatcherId != self.dispatcherId:
|
|
serverAccessor = serverAccessor.copy()
|
|
serverAccessor['isDefault'] = 1
|
|
return serverAccessor
|
|
return virtualServer.serverAccessors[serverId]
|
|
|
|
def init(self):
|
|
self.randomGenerator = whrandom.whrandom()
|
|
Server.init(self)
|
|
|
|
def loadConfigOptions(self):
|
|
Server.loadConfigOptions(self)
|
|
|
|
configContext = context.get(_level = 'config')
|
|
|
|
autorizedHostNames = commonTools.getConfig(
|
|
'Security', 'RestrictRegisterTo', default = '')
|
|
autorizedHostNames = autorizedHostNames.replace(',', ' ')
|
|
autorizedHostNames = autorizedHostNames.strip().split()
|
|
configContext.setVar('autorizedHostNames', autorizedHostNames)
|
|
|
|
def registerDispatcherId(self, dispatcherId):
|
|
"""Register a new dispatcherId to the dispatcher."""
|
|
|
|
virtualServer = self.getVirtualServer(None)
|
|
|
|
# Ensure that dispatcherId has a valid syntax.
|
|
dispatcherId = commonTools.extractDispatcherId(dispatcherId)
|
|
|
|
if dispatcherId in virtualServer.dispatcherIds:
|
|
return
|
|
|
|
clientToken = context.getVar('clientToken')
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
raise faults.UnknownApplicationToken(clientToken)
|
|
clientId = virtualServer.virtualServerIds[clientToken]
|
|
|
|
virtualServer.dispatcherIds.append(dispatcherId)
|
|
print 'Registered dispatcher id "%s"' % dispatcherId
|
|
|
|
if virtualServer.serverAccessors.has_key(clientId):
|
|
clientAccessor = virtualServer.serverAccessors[clientId]
|
|
else:
|
|
clientAccessor = virtualServer.defaultAccessors[
|
|
commonTools.extractRole(clientId)]
|
|
for serverInfo in virtualServer.serverInfos.values():
|
|
serverAccessor = serverInfo['accessor']
|
|
if serverAccessor == clientAccessor:
|
|
# We must avoid to call the VirtualHosts server back, because
|
|
# when it calls registerDispatcherId at initialization, it is
|
|
# not yet ready to receive public calls (serve_forever has not
|
|
# yet been called).
|
|
continue
|
|
serverId = commonTools.makeApplicationId(
|
|
'glasnost://%s' % serverAccessor['serverHostName'],
|
|
serverInfo['role'])
|
|
print 'Calling addDispatcher(%s) for %s' % (dispatcherId, serverId)
|
|
callServer(serverId, 'addDispatcher', [
|
|
serverId, getApplicationToken(),
|
|
context.getVar('userToken'), dispatcherId])
|
|
print 'Called addDispatcher(%s) for %s' % (dispatcherId, serverId)
|
|
|
|
def registerToDispatcher(self):
|
|
applicationId = context.getVar('applicationId')
|
|
applicationToken = self.getApplicationToken(applicationId)
|
|
context.getVar('applicationTokens')[applicationId] = applicationToken
|
|
context.push(clientToken = applicationToken)
|
|
self.registerServer(self.hostName, self.port)
|
|
|
|
virtualServer = self.getVirtualServer(None)
|
|
for dispatcherId in virtualServer.dispatcherIds:
|
|
applicationToken = self.getApplicationToken(dispatcherId)
|
|
context.getVar('applicationTokens')[dispatcherId] \
|
|
= applicationToken
|
|
self.registerVirtualServer(self.hostName, self.port, dispatcherId)
|
|
context.pull()
|
|
|
|
def registerPublicMethods(self):
|
|
Server.registerPublicMethods(self)
|
|
self.registerPublicMethod('getApplicationId')
|
|
self.registerPublicMethod('getApplicationToken')
|
|
self.registerPublicMethod('getRegisteredRoles')
|
|
self.registerPublicMethod('getServerAccessor')
|
|
self.registerPublicMethod('registerDispatcherId')
|
|
self.registerPublicMethod('registerServer')
|
|
self.registerPublicMethod('registerVirtualServer')
|
|
self.registerPublicMethod('unregisterServer')
|
|
self.registerPublicMethod('unregisterVirtualServer')
|
|
|
|
def registerServer(self, serverHostName, serverPort):
|
|
virtualServer = self.getVirtualServer(None)
|
|
clientToken = context.getVar('clientToken')
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
raise faults.UnknownApplicationToken(clientToken)
|
|
clientId = virtualServer.virtualServerIds[clientToken]
|
|
clientRole = commonTools.extractRole(clientId)
|
|
|
|
serverNameAndPort = '%s:%s' % (serverHostName, serverPort)
|
|
autorizedHostNames = context.getVar('autorizedHostNames')
|
|
if autorizedHostNames and not serverHostName in autorizedHostNames:
|
|
raise faults.ServerRegistrationDenied(
|
|
serverHostName, serverPort)
|
|
|
|
accessor = {
|
|
'serverHostName': serverHostName,
|
|
'serverPort': serverPort,
|
|
}
|
|
virtualServer.serverInfos[serverNameAndPort] = {
|
|
'accessor': accessor,
|
|
'role': clientRole,
|
|
}
|
|
|
|
virtualServer.defaultAccessors[clientRole] = accessor
|
|
virtualServer.markCoreAsDirty()
|
|
print 'Registered server %s (role = %s)' % (
|
|
serverNameAndPort, clientRole)
|
|
|
|
return virtualServer.dispatcherIds
|
|
|
|
def registerVirtualServer(self, serverHostName, serverPort, serverId):
|
|
virtualServer = self.getVirtualServer(None)
|
|
# Ensure that serverId has a valid syntax.
|
|
serverId = commonTools.extractServerId(serverId)
|
|
clientToken = context.getVar('clientToken')
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
raise faults.UnknownApplicationToken(clientToken)
|
|
|
|
serverDispatcherId = commonTools.extractDispatcherId(serverId)
|
|
if not serverDispatcherId in virtualServer.dispatcherIds:
|
|
raise faults.UnknownDispatcherInId(serverId)
|
|
|
|
serverNameAndPort = '%s:%s' % (serverHostName, serverPort)
|
|
if not virtualServer.serverInfos.has_key(serverNameAndPort):
|
|
raise faults.UnregisteredServer(serverHostName, serverPort)
|
|
|
|
virtualServer.serverAccessors[serverId] = virtualServer.serverInfos[
|
|
serverNameAndPort]['accessor']
|
|
print 'Registered virtual server %s (for %s:%s)' % (
|
|
serverId, serverHostName, serverPort)
|
|
virtualServer.markCoreAsDirty()
|
|
|
|
def unregisterServer(self, serverHostName, serverPort):
|
|
virtualServer = self.getVirtualServer(None)
|
|
clientToken = context.getVar('clientToken')
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
raise faults.UnknownApplicationToken(clientToken)
|
|
serverNameAndPort = '%s:%s' % (serverHostName, serverPort)
|
|
if not virtualServer.serverInfos.has_key(serverNameAndPort):
|
|
raise faults.UnregisteredServer(serverHostName, serverPort)
|
|
serverInfo = virtualServer.serverInfos[serverNameAndPort]
|
|
serverAccessor = serverInfo['accessor']
|
|
|
|
# Unregister every virtual servers running on this server.
|
|
for virtualServerId, virtualServerAccessor in \
|
|
virtualServer.serverAccessors.items():
|
|
if virtualServerAccessor == serverAccessor:
|
|
del virtualServer.serverAccessors[virtualServerId]
|
|
|
|
del virtualServer.defaultAccessors[serverAccessor['role']]
|
|
del virtualServer.serverInfos[serverNameAndPort]
|
|
virtualServer.markCoreAsDirty()
|
|
|
|
def unregisterVirtualServer(self, serverId):
|
|
virtualServer = self.getVirtualServer(None)
|
|
clientToken = context.getVar('clientToken')
|
|
if not virtualServer.virtualServerIds.has_key(clientToken):
|
|
raise faults.UnknownApplicationToken(clientToken)
|
|
|
|
if not virtualServer.serverAccessors.has_key(serverId):
|
|
raise faults.UnknownServerId(serverId)
|
|
del virtualServer.serverAccessors[serverId]
|
|
virtualServer.markCoreAsDirty()
|
|
|
|
dispatcher = Dispatcher()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
dispatcher.launch(applicationName, applicationRole)
|