This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/servers/VirtualHostsServer/VirtualHostsServer.py

430 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 Virtual Hosts Server"""
__version__ = '$Revision$'[11:-2]
from fnmatch import fnmatch
import sys
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)
import glasnost
from glasnost.common.VirtualHostsCommon import *
import glasnost.common.faults as faults
import glasnost.common.tools_new as commonTools
import glasnost.common.xhtmlgenerator as X
from glasnost.server.ObjectsServer import register, ObjectServerMixin, \
AdminServerMixin, ObjectsServer, ObjectsVirtualServer
from glasnost.server.tools import *
from glasnost.proxy.DispatcherProxy import getApplicationToken, \
registerDispatcherId, registerVirtualServer
applicationName = 'VirtualHostsServer'
applicationRole = 'virtualhosts'
dispatcher = None
class AdminVirtualHosts(AdminServerMixin, AdminVirtualHostsCommon):
pass
register(AdminVirtualHosts)
class VirtualHost(ObjectServerMixin, VirtualHostCommon):
strings = None
strings_keyType = 'string'
strings_type = 'mapping'
strings_valueType = 'string'
def checkModifyIsPossible(self, changes, givenSlotNames = None):
ObjectServerMixin.checkModifyIsPossible(
self, changes, givenSlotNames = givenSlotNames)
objectsByHostName = self.getServer().virtualServer.objectsByHostName
if (not givenSlotNames or 'hostName' in givenSlotNames) \
and changes.hostName != self.hostName \
and changes.hostName is not None:
if objectsByHostName.has_key(changes.hostName) \
and changes.id != objectsByHostName[changes.hostName].id:
raise faults.DuplicateHostName(changes.hostName)
def clear(self):
objectsByHostName = self.getServer().virtualServer.objectsByHostName
del(objectsByHostName[self.hostName])
def importFromXmlRpc(self, virtualHostImport, parentSlot = None):
hostName = self.hostName
VirtualHostCommon.importFromXmlRpc(
self, virtualHostImport, parentSlot = parentSlot)
objectsByHostName = self.getServer().virtualServer.objectsByHostName
if self.hostName != hostName:
if hostName is not None:
del objectsByHostName[hostName]
if self.hostName is not None:
if objectsByHostName.has_key(self.hostName) \
and self.id != objectsByHostName[self.hostName].id:
raise faults.DuplicateHostName(self.hostName)
objectsByHostName[self.hostName] = self
def modify(self, changes, givenSlotNames = None):
objectsByHostName = self.getServer().virtualServer.objectsByHostName
hostName = self.hostName
ObjectServerMixin.modify(
self, changes, givenSlotNames = givenSlotNames)
if self.hostName != hostName:
if hostName is not None:
del objectsByHostName[hostName]
if self.hostName is not None:
objectsByHostName[self.hostName] = self
register(VirtualHost)
class VirtualHostsVirtualServer(ObjectsVirtualServer):
objectsByHostName = None
def init(self):
ObjectsVirtualServer.init(self)
self.objectsByHostName = {}
def initFromOldData(self, data):
ObjectsVirtualServer.initFromOldData(self, data)
self.objectsByHostName = {}
for object in self.objects.values():
if object.hostName is not None:
self.objectsByHostName[object.hostName] = object
class VirtualHostsServer(VirtualHostsCommonMixin, ObjectsServer):
VirtualServer = VirtualHostsVirtualServer
hasMultipleVirtualServers = 0
def addObjectXmlRpc(self, objectImport):
"""Create a new virtual host on the server.
Keyword argument:
=================
*objectImport*:
The new object in XML RPC dictionnary format.
Returns:
========
The new virtual host ID.
Exceptions:
===========
*faults.UserAccessDenied*:
The user is not in the admin set.
*standard Exception*:
- The thing category 'object' doesn't exists. (very grave !)
- The adminImport __thingName__ key is not a valid Thing name.
*KeyError*:
+ The virtual server ID does not correspond to a instanciated
virtual server.
+ No client ID corresponding to the client token.
*AttributeError*:
The default dispatcherId contained in the object is not a string.
*faults.UnknownApplicationToken*:
The given application token is not in the dispatcher virtual server
ids dictionnary.
*OSError*:
The apache configuration directory does not exists and cannot be
created.
*IOError*:
The vhost file cannot be writen, or the templace config file cannot
be read.
"""
objectId = ObjectsServer.addObjectXmlRpc(self, objectImport)
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectId)
if not object.defaultDispatcherId:
# BAD, we remove it before it harms somebody
del virtualServer.objects[objectId]
virtualServer.markObjectAsDeleted(objectId)
virtualServer.markCoreAsDirty()
raise faults.BadValue()
if object.defaultDispatcherId[-1] == '/':
object.defaultDispatcherId = object.defaultDispatcherId[:-1]
virtualServer.markObjectAsDirty(object)
newDispatcherId = object.defaultDispatcherId
registerDispatcherId(newDispatcherId)
newVirtualServerId = commonTools.makeApplicationId(
newDispatcherId, self.applicationRole)
context.push(
applicationId = newVirtualServerId,
)
context.getVar('applicationTokens')[newVirtualServerId] = \
getApplicationToken()
context.pull()
registerVirtualServer(self.hostName, self.port, newVirtualServerId)
self.updateApacheVHost(object)
return objectId
def convertVirtualServersIds(self, sourceDispatcherId,
destinationDispatcherId):
self.virtualServer.convertIds(
sourceDispatcherId, destinationDispatcherId)
self.virtualServer.markAllAsDirtyFIXME()
return None
def exportVirtualServer(self, virtualServerId, exportDirectoryPath):
return None
def getDefaultVirtualHost(self):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.admin.defaultVirtualHostId:
raise faults.MissingItem('default virtual host')
return self.getObjectXmlRpc(self.admin.defaultVirtualHostId)
def getHostNameXmlRpc(self):
"""Return the url of the virtual server."""
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
dispatcherId = commonTools.extractDispatcherId(
virtualServerId).lower()
for object in virtualServer.objects.values():
if dispatcherId == commonTools.extractDispatcherId(
object.defaultDispatcherId).lower():
return utf8('http://' + object.hostName)
raise faults.MissingItem(dispatcherId)
def getObjectByHostName(self, hostName):
"""Return the first virtual host with the given host name."""
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.objectsByHostName:
# The is no virtual host defined. Create one with the requested
# host name.
object = commonTools.newThing(
'object', 'virtualhosts.VirtualHost')
object.title = 'Glasnost'
object.hostName = hostName
object.defaultDispatcherId = 'glasnost://%s' % hostName
object.language = 'en'
self.addObjectXmlRpc(object.exportToXmlRpc())
if not virtualServer.objectsByHostName.has_key(hostName):
for k in virtualServer.objectsByHostName.keys():
if fnmatch(hostName, k):
hostName = k
break
else:
raise faults.MissingItem(hostName)
object = virtualServer.objectsByHostName[hostName]
return object
def getObjectByHostNameXmlRpc(self, hostName):
hostName = iso8859_15(hostName)
return self.getObjectByHostName(hostName).exportToXmlRpc()
def getObjectIdByHostNameXmlRpc(self, hostName):
hostName = iso8859_15(hostName)
return self.getObjectByHostName(hostName).id
def hasDispatcherIdXmlRpc(self, dispatcherId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
dispatcherId = iso8859_15(dispatcherId)
for object in virtualServer.objects.values():
if object.defaultDispatcherId == dispatcherId:
return 1
return 0
def hasHostNameXmlRpc(self, hostName):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
hostName = iso8859_15(hostName)
if virtualServer.objectsByHostName.has_key(hostName):
return 1
for k in virtualServer.objectsByHostName.keys():
if fnmatch(hostName, k):
return 1
return 0
def importVirtualServer(self, virtualServerId, importDirectoryPath):
return None
def modifyObjectXmlRpc(self, objectImport):
version = ObjectsServer.modifyObjectXmlRpc(self, objectImport)
id = objectImport['id']
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(id)
self.updateApacheVHost(object)
return version
def registerPublicMethods(self):
ObjectsServer.registerPublicMethods(self)
self.registerPublicMethod('getHostName', self.getHostNameXmlRpc)
self.registerPublicMethod('getDefaultVirtualHost',
self.getDefaultVirtualHost)
self.registerPublicMethod('getObjectByHostName',
self.getObjectByHostNameXmlRpc)
self.registerPublicMethod('getObjectIdByHostName',
self.getObjectIdByHostNameXmlRpc)
self.registerPublicMethod('hasDispatcherId',
self.hasDispatcherIdXmlRpc)
self.registerPublicMethod('hasHostName', self.hasHostNameXmlRpc)
def registerToDispatcher(self):
ObjectsServer.registerToDispatcher(self)
for virtualHost in self.virtualServer.objects.values():
newDispatcherId = virtualHost.defaultDispatcherId
registerDispatcherId(newDispatcherId)
newVirtualServerId = commonTools.makeApplicationId(
newDispatcherId, self.applicationRole)
context.push(
applicationId = newVirtualServerId,
)
context.getVar('applicationTokens')[newVirtualServerId] = \
getApplicationToken()
context.pull()
registerVirtualServer(self.hostName, self.port, newVirtualServerId)
def repairVirtualServer(self, virtualServer, version):
changed = 0
if version < 5001:
changed = 1
virtualServer.objectsByHostName = {}
for object in virtualServer.objects.values():
if object.hostName is not None:
virtualServer.objectsByHostName[object.hostName] = object
if version < 5004:
changed = virtualServer.admin.repair(5004) or changed
for id, object in virtualServer.objects.items():
changed = object.repair(5004) or changed
if version <= 1009000:
admin = virtualServer.admin
adminId = '%s/%s/__admin__' % (
commonTools.extractDispatcherId(
virtualServer.virtualServerId),
self.applicationRole)
if admin.id != adminId:
changed = 1
admin.id = adminId
if version <= 1033000:
for object in virtualServer.objects.values():
if object.defaultDispatcherId[-1] == '/':
object.defaultDispatcherId = object.defaultDispatcherId[
:-1]
changed = 1
if changed:
virtualServer.markAllAsDirtyFIXME()
def updateApacheVHost(self, object):
"""Update the apache virtual host configuration.
Get the apache config template from the vistual host server data
directory.
Create the apache vhost files and fill them to add the given object as
a new virtual host.
Keyword argument
================
*object*:
The virtual host object instance to add to the apache virtual
host(s).
Exceptions
==========
*OSError*:
The apache configuration directory does not exists and cannot be
created.
*IOError*:
The vhost file cannot be writen, or the templace config file cannot
be read.
"""
hostName = object.hostName
templateFileName = '%s/%s/apache-template.conf' % (
self.dataDirectoryPath, applicationRole)
if not os.path.exists(templateFileName):
return
if not os.path.exists('%s/%s/apache' % (
self.dataDirectoryPath, applicationRole)):
try:
os.mkdir('%s/%s/apache' % (
self.dataDirectoryPath, applicationRole))
except OSError:
return
apacheConfFileName = '%s/%s/apache/vhost-%s.conf' % (
self.dataDirectoryPath, applicationRole, hostName)
try:
open(apacheConfFileName, 'w').write(
open(templateFileName).read() % {'hostName': hostName})
except IOError:
pass
virtualHostsServer = VirtualHostsServer()
if __name__ == "__main__":
virtualHostsServer.launch(applicationName, applicationRole)