fastcgi: Enable php and trac for chimara-if.org.
[matthijs/servers/drsnuggles.git] / etc / init.d / fastcgi
1 #!/usr/bin/python
2 import os
3 import re
4 import pwd
5 import grp
6 import shutil
7 import stat
8
9 ROOT_DIR="/data/www"
10
11 # SITES = [(sitename, application_list)]
12 # application_list = [application_name, (application_name, command, ...)]
13 # Here, sitename is the name of the site. This folder name should exist below ROOT_DIR and
14 # is also used below SOCKET_DIR. The site name is also translated to a user and
15 # group name by replacing dots by dashes and prepending USER_PREFIX and
16 # GROUP_PREFIX.
17 #
18 # application_list specifies the applications to start for this site. These can
19 # be generic (when only application_name is given), in which case the command
20 # is looked up in APPLICATIONS using the application_name. For a site-specific
21 # application, command is the command that should be run. It will be prefixed
22 # with the site's root dir, if is not an absolute path.
23
24  
25 SITES=[
26         ('stderr.nl',             ['php', ('trac', 'applications/trac/trac.fcgi')]),
27         ('stdin.nl',              ['php']),
28         ('stdout.nl',             ['php']),
29         ('ninniach.nl',           ['php']),
30         ('blues-brothers.eu',     ['php']),
31         ('evolution-events.nl',   ['php',
32             ('wipi', 'applications/wipi/wipi.fcgi'),
33             ('hunternet', 'applications/lexnet/manage.py runfcgi'),
34             ('xerxes', 'applications/xerxes/manage.py runfcgi'),
35             ('dorestad-bookings', 'applications/dorestad-bookings/manage.py.local runfcgi debug=true'),
36         ]),
37 #       ('stdio.flexvps.nl',      ['php']),
38 #       ('foresightsecurity.nl',  ['php']),
39         ('chimara-if.org',        ['php', ('trac', 'applications/trac/trac.fcgi')]),
40 ]
41
42 # Generic applications that can be run for any site
43 # Maps application_name to application_command. application_command will be
44 # prefixed with the site's root dir, if it is not an absolute path.
45 APPLICATIONS={"php": "/usr/bin/php-cgi"}
46
47 # Kill these procs before starting new ones. Only processes of these names that
48 # are run by the sites in SITES are killed. This is a bit hackish, we should
49 # really be using pidfiles...
50 KILL_PROCS=['php-cgi', 'manage.py', 'manage.py.local', 'trac.fcgi', 'wipi.fcgi']
51
52 ## ABSOLUTE path to the spawn-fcgi binary
53 SPAWNFCGI="/usr/bin/spawn-fcgi"
54
55 ## Dir in which to create the UNIX sockets to listen on
56 SOCKET_DIR="%s/var/fcgi" % (ROOT_DIR)
57
58 ## number of PHP children to spawn
59 PHP_FCGI_CHILDREN=2
60
61 ## maximum number of requests a single PHP process can serve before it is restarted
62 PHP_FCGI_MAX_REQUESTS=1000
63
64 # The user to run as, will be prefixed to the sitename
65 USER_PREFIX="httpd-"
66 # The group to run as.
67 SCRIPT_GROUP="httpd-users"
68 # The group that should be able to use the sockets created
69 HTTPD_GROUP="www-data"
70
71 # Will be postfixed to the site's root and exported in the PHPRC variable.
72 PHPRC_DIR="conf"
73
74 #### END OF CONFIG ####
75
76 for (site, apps) in SITES:
77         site_name = re.sub('\.', '-', site)
78
79         ## switch to the following user / group
80         user_id    = "%s%s" % (USER_PREFIX, site_name)
81         
82         # Find the site dir
83         site_dir   = os.path.join(ROOT_DIR, site)
84         socket_dir = os.path.join(SOCKET_DIR, site_name)
85
86         # Pass the site dir to all fastcgi processes
87         os.environ['SITE_DIR'] = site_dir
88
89         if not site_dir:
90                 raise Exception("Site dir does not exist: %s" % (site_dir))
91         
92         
93         # Kill existing processes first
94         for procname in KILL_PROCS:
95                 os.system('killall --user %s %s' % (user_id, procname))
96
97         # Remove old sockets
98         if os.path.exists(socket_dir): 
99                 shutil.rmtree(socket_dir)
100
101         # Create dir for sockets. Make owning group root and set group write
102         # permissions, so the mask field in the acl will not block out anything.
103         os.makedirs(socket_dir)
104         os.chown(socket_dir, pwd.getpwnam(user_id)[2], grp.getgrnam(HTTPD_GROUP)[2])
105         #os.chmod(socket_dir, stat.S_IRWXU)
106         
107         for app in apps:
108                 # Unpack app tuple or lookup app command in APPLICATIONS
109                 if isinstance(app, tuple):
110                         if len(app) == 2:
111                                 (app_name, app_command) = app
112                         else:
113                                 raise Exception("Wrong number of elements in site tuple: %s", app)
114                 else:
115                         app_name = app
116                         app_command = APPLICATIONS[app_name]
117         
118                 # Prefix with site dir if not an absolute path
119                 if not os.path.isabs(app_command):
120                         app_command = os.path.join(site_dir, app_command)
121
122                 # Create socket filename
123                 socket = os.path.join(socket_dir, app_name)
124
125                 # Build the command
126                 # TODO: Wrap this in env to clear up the environment
127                 spawnfcgi = '%s -s "%s" -u "%s" -g "%s"' % (SPAWNFCGI, socket, user_id, SCRIPT_GROUP)
128                 fcgiapp = ' -- %s' % (app_command)
129
130                 if app_name == 'php':
131                         os.environ['PHP_FCGI_MAX_REQUESTS'] = str(PHP_FCGI_MAX_REQUESTS)
132                         phprc = os.path.join(site_dir, PHPRC_DIR, 'php.ini')
133                         if os.path.exists(phprc):
134                                 #os.environ['PHPRC'] = phprc
135                                 fcgiapp   += ' -c %s' % (phprc)
136                         spawnfcgi += ' -C %s' % (PHP_FCGI_CHILDREN)
137
138
139                 print spawnfcgi + fcgiapp
140                 os.system(spawnfcgi + fcgiapp)
141
142                 # Ensure www-data can write to the socket :-S
143                 # Spawn-fcgi explicitely chmods the socket after creation, very
144                 # annoying
145                 os.chmod(socket, stat.S_IRWXU | stat.S_IRWXG)