diff --git a/docs/installation_iis.rst b/docs/installation_iis.rst --- a/docs/installation_iis.rst +++ b/docs/installation_iis.rst @@ -44,50 +44,24 @@ to run on the website and consequently, ISAPI Handler ............. -The ISAPI handler needs to be generated from a custom file. Imagining that the -Kallithea installation is in ``c:\inetpub\kallithea``, we would have a file in -the same directory called, e.g. ``dispatch.py`` with the following contents:: - - import sys +The ISAPI handler can be generated using:: - if hasattr(sys, "isapidllhandle"): - import win32traceutil - - import isapi_wsgi - - def __ExtensionFactory__(): - from paste.deploy import loadapp - from paste.script.util.logging_config import fileConfig - fileConfig('c:\\inetpub\\kallithea\\production.ini') - application = loadapp('config:c:\\inetpub\\kallithea\\production.ini') + paster install-iis my.ini --root=/ - def app(environ, start_response): - user = environ.get('REMOTE_USER', None) - if user is not None: - os.environ['REMOTE_USER'] = user - return application(environ, start_response) - - return isapi_wsgi.ISAPIThreadPoolHandler(app) +This will generate a ``dispatch.py`` file in the current directory that contains +the necessary components to finalize an installation into IIS. Once this file +has been generated, it is necessary to run the following command due to the way +that ISAPI-WSGI is made:: - if __name__=='__main__': - from isapi.install import * - params = ISAPIParameters() - sm = [ScriptMapParams(Extension="*", Flags=0)] - vd = VirtualDirParameters(Name="/", - Description = "ISAPI-WSGI Echo Test", - ScriptMaps = sm, - ScriptMapUpdate = "replace") - params.VirtualDirs = [vd] - HandleCommandLine(params) + python dispatch.py install -This script has two parts: First, when run directly using Python, it will -install a script map ISAPI handler into the root application of the default -website, and secondly it will be called from the ISAPI handler when invoked -from the website. +This accomplishes two things: generating an ISAPI compliant DLL file, +``_dispatch.dll``, and installing a script map handler into IIS for the +``--root`` specified above pointing to ``_dispatch.dll``. The ISAPI handler is registered to all file extensions, so it will automatically -be the one handling all requests to the website. When the website starts the -ISAPI handler, it will start a thread pool managed wrapper around the paster +be the one handling all requests to the specified root. When the website starts +the ISAPI handler, it will start a thread pool managed wrapper around the paster middleware WSGI handler that Kallithea runs within and each HTTP request to the site will be processed through this logic henceforth. diff --git a/kallithea/lib/paster_commands/install_iis.py b/kallithea/lib/paster_commands/install_iis.py new file mode 100644 --- /dev/null +++ b/kallithea/lib/paster_commands/install_iis.py @@ -0,0 +1,85 @@ +import os +import sys +from paste.script.appinstall import AbstractInstallCommand +from paste.script.command import BadCommand + +# Add location of top level folder to sys.path +from os.path import dirname as dn +rc_path = dn(dn(dn(os.path.realpath(__file__)))) +sys.path.append(rc_path) + +class Command(AbstractInstallCommand): + default_verbosity = 1 + max_args = 1 + min_args = 1 + summary = 'Setup IIS given a config file' + usage = 'CONFIG_FILE' + + description = ''' + Script for installing into IIS using isapi-wsgi. + ''' + parser = AbstractInstallCommand.standard_parser( + simulate=True, quiet=True, interactive=True) + parser.add_option('--virtualdir', + action='store', + dest='virtualdir', + default='/', + help='The virtual folder to install into on IIS') + + def command(self): + config_spec = self.args[0] + if not config_spec.startswith('config:'): + config_spec = 'config:' + config_spec + config_file = config_spec[len('config:'):].split('#', 1)[0] + config_file = os.path.join(os.getcwd(), config_file) + try: + import isapi_wsgi + except ImportError: + raise BadCommand('missing requirement: isapi-wsgi not installed') + + file = '''import sys + +if hasattr(sys, "isapidllhandle"): + import win32traceutil + +import isapi_wsgi +import os + +def __ExtensionFactory__(): + from paste.deploy import loadapp + from paste.script.util.logging_config import fileConfig + fileConfig('%(inifile)s') + application = loadapp('config:%(inifile)s') + + def app(environ, start_response): + user = environ.get('REMOTE_USER', None) + if user is not None: + os.environ['REMOTE_USER'] = user + return application(environ, start_response) + + return isapi_wsgi.ISAPIThreadPoolHandler(app) + +if __name__=='__main__': + from isapi.install import * + params = ISAPIParameters() + sm = [ScriptMapParams(Extension="*", Flags=0)] + vd = VirtualDirParameters(Name="%(virtualdir)s", + Description = "Kallithea", + ScriptMaps = sm, + ScriptMapUpdate = "replace") + params.VirtualDirs = [vd] + HandleCommandLine(params) +''' + + outdata = file % { + 'inifile': config_file.replace('\\', '\\\\'), + 'virtualdir': self.options.virtualdir + } + + dispatchfile = os.path.join(os.getcwd(), 'dispatch.py') + self.ensure_file(dispatchfile, outdata, False) + print 'generating', dispatchfile + + print ('run \'python "%s" install\' with administrative privileges ' + 'to generate the _dispatch.dll file and install it into the ' + 'default web site') % (dispatchfile,) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -180,5 +180,6 @@ setup( make-index=kallithea.lib.paster_commands.make_index:Command upgrade-db=kallithea.lib.dbmigrate:UpgradeDb celeryd=kallithea.lib.celerypylons.commands:CeleryDaemonCommand + install-iis=kallithea.lib.paster_commands.install_iis:Command """, )