On Nov 28, 2:55 pm, Brian <[EMAIL PROTECTED]> wrote: > > > This is a good question, and I haven't come to a conclusion. Probably > > > it'll be the Django built-in application-based authentication, > > > particular to each Django instance. There will be a master map of all > > > users to their respective Django instance. > > > That seems a bit like a chicken and egg problem. At the point that you > > need to make the decision as to which Django instance to use, you > > haven't yet logged in them in. Thus if you are going to try and use > > their own instance to log them in, that can't work. > > If usernames are unique, e.g. email addresses, there can be a map, > e.g.: > [EMAIL PROTECTED] => DjangoInstanceA, > [EMAIL PROTECTED] => DjangoInstanceB, > > This User-Instance mapping could happen prior to authentication if, > when the user submits login-information from a form, a process > (demultiplexer) decides based upon the username which Django instance > to direct the login-request to. The Django instance then handles all > subsequent requests. > > I don't know if this will actually work. > > > If you use one special Django instance to handle login, then issue is > > having any session information in that instance also used by the other > > instances such that when you go to actual instance on subsequent > > requests, it knows you are allowed to access it. > > Perhaps HTTP Basic authentication might be the simplest solution. :) > > > I'll describe any solution in terms of HTTP Basic authentication first > > and then can let you think about authentication when you see how the > > multiplexing is achieved. > > That'd be great!
Okay, the solution I am going to describe uses Apache/mod_wsgi. This is an Apache module specifically designed for hosting Python WSGI applications within Apache. The mod_wsgi module provides two modes of operations. The first is embedded mode, which works similar to mod_python in that applications run within the actual Apache child worker processes. The second mode is daemon mode, which is similar in some respects to fastcgi solutions, with applications running in distinct processes from Apache child worker processes, and with Apache child worker processes merely acting as a proxy to the WSGI application daemon processes. We will be using mod_wsgi daemon mode in this case, as it will allow for each Django instance to run in a separate process. How one would normally set up Apache/mod_wsgi for Django is described at: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango What we will be doing here goes beyond that, but please ensure you read that first and perhaps get a single Django instance running that way before contemplating the multiplexing arrangement described here. Getting back to what you wanted, you wanted multiple users to see a Django instance mounted at same URL, but for each to actually get a distinct instance associated with a distinct database. For this, as would normally be done, still use WSGIScriptAlias to mount the WSGI script file at the appropriate URL. Here we assume it will be root of web server. Thus: WSGIScriptAlias / /usr/local/django/mysite/apache/django.wsgi By default, this will have Django instance running in embedded mode so we want to override that. This would normally be done by configuring a daemon process group and delegating application to run in it. WSGIDaemonProcess django1 display-name=%{GROUP} WSGIProcessGroup django1 The 'display-name' option here means that 'ps' command will show '(wsgi:django1)' in output rather that 'httpd' process name. This will be important for later on. The way WSGIProcessGroup is used here means it is a static mapping, so although we might be able to create more daemon process groups, you would have to change the Apache configuration and restart Apache to be able to delegate application to run in different daemon process group. Obviously this isn't what we want. So, instead of a static mapping, we use ability of mod_wsgi for the process group to which application is delegated to be specified dynamically. There are actually a number of ways this can be done when using mod_wsgi, but will use a method which uses mod_rewrite as a helper. You indicated that there would be a cap on the number of instances of Django that need to be running at any one time. Thus, what we will do is pre define that many daemon process groups. WSGIDaemonProcess django1 display-name=%{GROUP} WSGIDaemonProcess django2 display-name=%{GROUP} WSGIDaemonProcess django3 display-name=%{GROUP} ... WSGIDaemonProcess djangon display-name=%{GROUP} We also want which daemon process group is used based on identity of logged in user. We will use HTTP Basic authentication as authentication as that is the easiest. As long as you run stuff through HTTPS using HTTP Basic authentication wouldn't be an issue. Before we get onto how to use user identity from HTTP Basic authentication, lets look at the dynamic mapping issue. To do this what we are going to define is: WSGIProcessGroup %{ENV:PROCESS_GROUP} What this says is that name of process group should instead be source from request environment variable called 'PROCESS_GROUP'. To set that, we are going to use a rewrite rule and source the value to set it to from a mapping file in the file system. Note using mapping file here as it allows the value to then be set outside of Apache configuration with Apache automatically picking up the change. Also key to when we move on to dealing with user identity. Adding that we then have: RewriteEngine On RewriteMap procmap txt:/usr/local/django/mysite/apache/procmap.txt RewriteRule . - [E=PROCESS_GROUP:${procmap:django|undefined}] WSGIProcessGroup %{ENV:PROCESS_GROUP} The 'procmap.txt' file will contain: django django1 This file is read by Apache and cached, but will be reread when it changes. With the file written as is, means that Django instance will be delegated to daemon process group called 'django1'. If you wanted it instead to run in daemon process group called 'django2', you would simply edit the 'procmap.txt' file and change it to: django django2 If for some reason the file didn't contain key 'django' used in rewrite rule, would use value of 'undefined' for process group name. Since no such daemon process group defined, then mod_wsgi would return 500 error to request indicating that no valid daemon process group. This sort of setup where delegation is manual may be a way of handling swapping between application versions when upgrading a site, but we need to introduce the identity of the user. I will not show how to setup HTTP Basic authentication as you just need to follow Apache documentation for that. Important thing to know is that in using HTTP Basic authentication, the identity of the user is then available to rewrite rules as "REMOTE_USER'. To use that, we then change above to: RewriteEngine On RewriteMap procmap txt:/usr/local/django/mysite/apache/procmap.txt RewriteRule . - [E=PROCESS_GROUP:${procmap:%{REMOTE_USER}| undefined}] WSGIProcessGroup %{ENV:PROCESS_GROUP} The difference here is that instead of lookup key in rewrite map being fixed value of 'django' we use the identity of the logged in user. The 'procmap.txt' file would then contain multiple entries, one per user who could access the site. graham django1 brian django2 macolm django3 Looking at that altogether, what we have is a pool of daemon process groups that can be used and a way of dynamically, via the mapping file, mapping different users requests into Django instances running in those different daemon process group. That is the multiplexing done, but it doesn't address how we have the instance in each daemon process group use a different database. Normally when using Django with Apache/mod_wsgi, the WSGI script file would contain: import os, sys sys.path.append('/usr/local/django') sys.path.append('/usr/local/django/mysite') os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() We don't want this though, as that would result in same Django settings module and thus same database configuration being used for each. So, what we are going to do is to split this into two parts. The WSGI script file will now just be: import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() All this is doing is setting the Django WSGI application entry point. It is not setting up sys.path or defining what the Django settings module is. For the latter, we will instead use a separate code file and load a unique one for each process group. To do that we use the WSGIImportScript directive to preload the configuration into the daemon process group at startup. One issue with WSGIImportScript though is that have to specify both the process group and application group (sub interpreter) into which the file should be loaded. Since at moment the application group will depend on name of host, let us instead force Django to run in main interpreter so can use known name. This is done using WSGIApplicationGroup directive. What we will then have is: WSGIScriptAlias / /usr/local/django/mysite/apache/django.wsgi WSGIApplicationGroup %{GLOBAL} RewriteEngine On RewriteMap procmap txt:/usr/local/django/mysite/apache/procmap.txt RewriteRule . - [E=PROCESS_GROUP:${procmap:%{REMOTE_USER}| undefined}] WSGIProcessGroup %{ENV:PROCESS_GROUP} WSGIDaemonProcess django1 display-name=%{GROUP} WSGIImportScript /usr/local/django/mysite/apache/django1.wsgi \ process-group=django1 application-group=%{GLOBAL} WSGIDaemonProcess django2 display-name=%{GROUP} WSGIImportScript /usr/local/django/mysite/apache/django2.wsgi \ process-group=django2 application-group=%{GLOBAL} WSGIDaemonProcess django3 display-name=%{GROUP} WSGIImportScript /usr/local/django/mysite/apache/django-config3.wsgi \ process-group=django3 application-group=%{GLOBAL} ... WSGIDaemonProcess djangon display-name=%{GROUP} WSGIImportScript /usr/local/django/mysite/apache/djangon.wsgi \ process-group=djangon application-group=%{GLOBAL} Presuming we only want to override database setting, 'django1.wsgi' would then have: import os, sys sys.path.append('/usr/local/django') sys.path.append('/usr/local/django/mysite') os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' import mysite.settings # Override per instance settings. mysite.settings.DATABASE_HOST = ... mysite.settings.DATABASE_NAME = ... ... The file for 'django2.wsgi' would be similar but different overrides for values. Instead of importing Django settings module and overriding them, you could also have distinct settings modules and just set DJANGO_SETTINGS_MODULE differently for each. What will now happen is that when Apache/mod_wsgi starts up a daemon process, it will import that configuration script which will set DJANGO_SETTINGS_MODULE and specify any overrides. When a request actually arrives, then the normal WSGI script file is loaded, along with actual Django code, but where configuration is based on the preloaded script. In this arrangement, the Django code will actually be lazily loaded, that is, only on first request. If you wanted to preload that as well, would just need to import necessary Django modules at end of config script. That is basically it and hopefully it makes sense. It may seem a bit complex, but what you want to do isn't normal. Also, it all could have been done a bit simpler if were using mod_wsgi 3.0 development code from subversion trunk as with that have a way of avoiding use of WSGIImportScript. This is because in that next version, name of daemon process group is actually available from within WSGI script file at global scope. Thus could have setting DJANGO_SETTINGS_MODULE in WSGI script file such that it used name of process group. For example: import mod_wsgi os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.%ssettings' % mod_wsgi.process_group Then all we need to do is have separate Django settings modules for the instance in each process group. The only thing to know cover is what to do when introducing and/or removing users. For that the steps would be: 1. Modify appropriate 'djangon.wsgi' config file referenced by WSGIImportScript. 2. Use 'ps' to identity PID that that daemon process and send it SIGINT. This will cause it to shutdown and restart. 3. Modify 'procpmap.txt' file to add in entry mapping new user to appropriate 'djangon' process group. 4. Add new user into authentication user database. For deletion, opposite done. Anyway, work through that and see if it makes any sense at all. As I said, could be a bit cleaner if using mod_wsgi 3.0 development version, or if you want to make a 4 line code change to mod_wsgi 2.X version you use. Could well be worth making the change just to make it that little bit simpler. BTW, also note this is all just typed in out of my head, I haven't actually gone and tested it, although believe it should work. The only issue you might run across is that the WSGIImportScript directive at the moment actually has to go outside of any VirtualHost containers where as WSGIDaemonProcess it applies to can be inside. There is a ticket for mod_wsgi to address this, but haven't got around to fixing it. If there are any questions, let me know. Graham --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---