1
2 """
3 Plugin for our configuring the OMERO.web installation
4
5 Copyright 2009 University of Dundee. All rights reserved.
6 Use is subject to license terms supplied in LICENSE.txt
7
8 """
9
10 from exceptions import Exception
11 from datetime import datetime
12 from omero.cli import BaseControl, CLI
13 from omeroweb import settings
14 import omero.java
15 import platform
16 import time
17 import sys
18 import os
19 import re
20
21
22 CONFIG_TABLE_FMT = " %-35.35s %-8s %r\n"
23 CONFIG_TABLE = CONFIG_TABLE_FMT % ("Key", "Default?", "Current value")
24
25 for key in sorted(settings.CUSTOM_SETTINGS_MAPPINGS):
26 global_name, default_value, mapping, using_default = settings.CUSTOM_SETTINGS_MAPPINGS[key]
27 global_value = getattr(settings, global_name, "(unset)")
28 CONFIG_TABLE += CONFIG_TABLE_FMT % (key, using_default, global_value)
29
30 HELP="""OMERO.web configuration/deployment tools
31
32 Configuration:
33
34 Configuration for OMERO.web takes place via the
35 omero config commands. The configuration values
36 which are checked are as below:
37
38 %s
39
40 Example Nginx usage:
41
42 omero config set omero.web.debug true
43 omero config set omero.web.application_server fastcgi
44 omero web config nginx --http=8000 >> nginx.conf
45 omero web start
46 nginx -c `pwd`/nginx.conf
47 omero web status
48 omero web stop
49 nginx -s stop
50
51 """ % CONFIG_TABLE
52
53
55
92
94 parts = APPLICATION_HOST.split(':')
95 if len(parts) != 3:
96 self.ctx.die(656, "Invalid application host: %s" % ":".join(parts))
97 try:
98 host = parts[1]
99 while host.startswith(r"/"):
100 host = host[1:]
101 port = parts[2]
102 port = re.search(r'^(\d+).*', port).group(1)
103 port = int(port)
104 return (host, port)
105 except Exception, e:
106 self.ctx.die(567, "Badly formed domain: %s -- %s" % (":".join(parts), e))
107
109 if not args.type:
110 self.ctx.out("Available configuration helpers:\n - nginx, apache\n")
111 else:
112 server = args.type
113 host, port = self.host_and_port(settings.APPLICATION_HOST)
114 if args.http:
115 port = args.http
116 if settings.APPLICATION_SERVER == settings.FASTCGITCP:
117 if settings.APPLICATION_SERVER_PORT == port:
118 self.ctx.die(678, "Port conflict: HTTP(%s) and fastcgi-tcp(%s)." % \
119 (port, settings.APPLICATION_SERVER_PORT))
120 if server == "nginx":
121 if settings.APPLICATION_SERVER == settings.FASTCGITCP:
122 fastcgi_pass = "%s:%s" % (settings.APPLICATION_SERVER_HOST,
123 settings.APPLICATION_SERVER_PORT)
124 else:
125 fastcgi_pass = "unix:%s/var/django_fcgi.sock" % self.ctx.dir
126 c = file(self.ctx.dir / "etc" / "nginx.conf.template").read()
127 d = {
128 "ROOT":self.ctx.dir,
129 "OMEROWEBROOT":self.ctx.dir / "lib" / "python" / "omeroweb",
130 "HTTPPORT":port,
131 "FASTCGI_PASS":fastcgi_pass,
132 }
133 self.ctx.out(c % d)
134 if server == "apache":
135 if settings.APPLICATION_SERVER == settings.FASTCGITCP:
136 fastcgi_external = '-host %s:%s' % \
137 (settings.APPLICATION_SERVER_HOST,
138 settings.APPLICATION_SERVER_PORT)
139 else:
140 fastcgi_external = '-socket "%s/var/django_fcgi.sock"' % \
141 self.ctx.dir
142 stanza = """###
143 ### Stanza for OMERO.web created %(NOW)s
144 ###
145 FastCGIExternalServer "%(ROOT)s/var/omero.fcgi" %(FASTCGI_EXTERNAL)s
146
147 <Directory "%(ROOT)s/var">
148 Options -Indexes FollowSymLinks
149 Order allow,deny
150 Allow from all
151 </Directory>
152
153 <Directory "%(MEDIA)s">
154 Options -Indexes FollowSymLinks
155 Order allow,deny
156 Allow from all
157 </Directory>
158
159 Alias /appmedia %(MEDIA)s
160 Alias / "%(ROOT)s/var/omero.fcgi/"
161 """
162 d = {
163 "ROOT":self.ctx.dir,
164 "MEDIA":self.ctx.dir / "lib" / "python" / "omeroweb" / "media",
165 "OMEROWEBROOT":self.ctx.dir / "lib" / "python" / "omeroweb",
166 "FASTCGI_EXTERNAL":fastcgi_external,
167 "NOW":str(datetime.now()),
168 }
169 self.ctx.out(stanza % d)
170
194
196 location = self.ctx.dir / "lib" / "python" / "omeroweb"
197 if not args.appname:
198 apps = [x.name for x in filter(lambda x: x.isdir() and (x / 'scripts' / 'enable.py').exists(), location.listdir())]
199 iapps = map(lambda x: x.startswith('omeroweb.') and x[9:] or x, settings.INSTALLED_APPS)
200 apps = filter(lambda x: x not in iapps, apps)
201 self.ctx.out('[enableapp] available apps:\n - ' + '\n - '.join(apps) + '\n')
202 else:
203 for app in args.appname:
204 args = ["python", location / app / "scripts" / "enable.py"]
205 rv = self.ctx.call(args, cwd = location)
206 if rv != 0:
207 self.ctx.die(121, "Failed to enable '%s'.\n" % app)
208 else:
209 self.ctx.out("App '%s' was enabled\n" % app)
210 args = ["python", "manage.py", "syncdb", "--noinput"]
211 rv = self.ctx.call(args, cwd = location)
212 self.syncmedia(None)
213
215 location = self.ctx.dir / "lib" / "python" / "omeroweb"
216 args = ["python", "-i", location / "../omero/gateway/scripts/dbhelpers.py"]
217 os.environ['ICE_CONFIG'] = self.ctx.dir / "etc" / "ice.config"
218 os.environ['PATH'] = os.environ.get('PATH', '.') + ':' + self.ctx.dir / 'bin'
219 os.environ['DJANGO_SETTINGS_MODULE'] = os.environ.get('DJANGO_SETTINGS_MODULE', 'omeroweb.settings')
220 rv = self.ctx.call(args, cwd = location)
221
222 - def test(self, args):
223 location = self.ctx.dir / "lib" / "python" / "omeroweb"
224 cargs = ["coverage","-x", "manage.py", "test"]
225 if args.arg:
226 cargs.append(args.arg)
227 os.environ['ICE_CONFIG'] = self.ctx.dir / "etc" / "ice.config"
228 os.environ['PATH'] = os.environ.get('PATH', '.') + ':' + self.ctx.dir / 'bin'
229 rv = self.ctx.call(cargs, cwd = location)
230
232 location = self.ctx.dir / "lib" / "python" / "omeroweb"
233 cargs = ["python", "seleniumtests.py"]
234 location = location / args.djangoapp / "tests"
235 print location
236 rv = self.ctx.call(cargs, cwd = location )
237
238 - def call (self, args):
239 try:
240 location = self.ctx.dir / "lib" / "python" / "omeroweb"
241 cargs = []
242 appname = args.appname
243 scriptname = args.scriptname.split(' ')
244 if len(scriptname) > 1:
245 cargs.append(scriptname[0])
246 scriptname = ' '.join(scriptname[1:])
247 else:
248 scriptname = scriptname[0]
249 cargs.extend([location / appname / "scripts" / scriptname] + args.arg)
250 print cargs
251 os.environ['DJANGO_SETTINGS_MODULE'] = 'omeroweb.settings'
252 os.environ['ICE_CONFIG'] = self.ctx.dir / "etc" / "ice.config"
253 os.environ['PATH'] = os.environ.get('PATH', '.') + ':' + self.ctx.dir / 'bin'
254 rv = self.ctx.call(cargs, cwd = location)
255 except:
256 import traceback
257 print traceback.print_exc()
258
259
261
262 import omeroweb.settings as settings
263 link = ("%s:%s" % (settings.APPLICATION_SERVER_HOST,
264 settings.APPLICATION_SERVER_PORT))
265 location = self.ctx.dir / "lib" / "python" / "omeroweb"
266 self.ctx.out("Starting OMERO.web... ", newline=False)
267 cache_backend = getattr(settings, 'CACHE_BACKEND', None)
268 if cache_backend is not None and cache_backend.startswith("file:///"):
269 cache_backend = cache_backend[7:]
270 if "Windows" != platform.system() \
271 and not os.access(cache_backend, os.R_OK|os.W_OK):
272 self.ctx.out("[FAILED]")
273 self.ctx.out("CACHE_BACKEND '%s' not writable or missing." % \
274 getattr(settings, 'CACHE_BACKEND'))
275 return 1
276 deploy = getattr(settings, 'APPLICATION_SERVER')
277
278
279 if deploy in (settings.FASTCGI_TYPES):
280 if "Windows" == platform.system():
281 self.ctx.out("""
282 WARNING: Unless you **really** know what you are doing you should NOT be
283 using bin\omero web start on Windows with FastCGI.
284 """)
285 pid_path = self.ctx.dir / "var" / "django.pid"
286 pid_num = None
287
288 if pid_path.exists():
289 pid_txt = pid_path.text().strip()
290 try:
291 pid_num = int(pid_txt)
292 except:
293 pid_path.remove()
294 self.ctx.err("Removed invalid %s: '%s'" % (pid_path, pid_txt))
295
296 if pid_num is not None:
297 try:
298 os.kill(pid_num, 0)
299 self.ctx.die(606, "%s exists! Use 'web stop' first" % pid_path)
300 except OSError:
301 pid_path.remove()
302 self.ctx.err("Removed stale %s" % pid_path)
303
304 if deploy == settings.FASTCGI:
305 cmd = "python manage.py runfcgi workdir=./"
306 cmd += " method=prefork socket=%(base)s/var/django_fcgi.sock"
307 cmd += " pidfile=%(base)s/var/django.pid daemonize=true"
308 cmd += " maxchildren=5 minspare=1 maxspare=5 maxrequests=400"
309 django = (cmd % {'base': self.ctx.dir}).split()
310 rv = self.ctx.popen(args=django, cwd=location)
311 elif deploy == settings.FASTCGITCP:
312 cmd = "python manage.py runfcgi workdir=./"
313 cmd += " method=prefork host=%(host)s port=%(port)s"
314 cmd += " pidfile=%(base)s/var/django.pid daemonize=true"
315 cmd += " maxchildren=5 minspare=1 maxspare=5 maxrequests=400"
316 django = (cmd % {'base': self.ctx.dir,
317 'host': settings.APPLICATION_SERVER_HOST,
318 'port': settings.APPLICATION_SERVER_PORT}).split()
319 rv = self.ctx.popen(args=django, cwd=location)
320 else:
321 django = ["python","manage.py","runserver", link, "--noreload"]
322 rv = self.ctx.call(django, cwd = location)
323 self.ctx.out("[OK]")
324 return rv
325
326
328 location = self.ctx.dir / "lib" / "python" / "omeroweb"
329 self.ctx.out("OMERO.web status... ", newline=False)
330 import omeroweb.settings as settings
331 deploy = getattr(settings, 'APPLICATION_SERVER')
332 cache_backend = getattr(settings, 'CACHE_BACKEND', None)
333 if cache_backend is not None:
334 cache_backend = ' (CACHE_BACKEND %s)' % cache_backend
335 else:
336 cache_backend = ''
337 rv = 0
338 if deploy in settings.FASTCGI_TYPES:
339 try:
340 f=open(self.ctx.dir / "var" / "django.pid", 'r')
341 pid = int(f.read())
342 except IOError:
343 self.ctx.out("[NOT STARTED]")
344 return rv
345 import signal
346 try:
347 os.kill(pid, 0)
348 self.ctx.out("[RUNNING] (PID %d)%s" % (pid, cache_backend))
349 except:
350 self.ctx.out("[NOT STARTED]")
351 return rv
352 else:
353 self.ctx.err("DEVELOPMENT: You will have to check status by hand!")
354 return rv
355
356 - def stop(self, args):
357 self.ctx.out("Stopping OMERO.web... ", newline=False)
358 import omeroweb.settings as settings
359 deploy = getattr(settings, 'APPLICATION_SERVER')
360 if deploy in settings.FASTCGI_TYPES:
361 if "Windows" == platform.system():
362 self.ctx.out("""
363 WARNING: Unless you **really** know what you are doing you should NOT be
364 using bin\omero web start on Windows with FastCGI.
365 """)
366 pid = 'Unknown'
367 pid_path = self.ctx.dir / "var" / "django.pid"
368 pid_text = pid_path.text().strip()
369 try:
370 try:
371 pid = int(pid_text)
372 import signal
373 os.kill(pid, 0)
374 except:
375 self.ctx.out("[FAILED]")
376 self.ctx.out("Django FastCGI workers (PID %s) not started?" % pid_text)
377 return
378 os.kill(pid, signal.SIGTERM)
379 self.ctx.out("[OK]")
380 self.ctx.out("Django FastCGI workers (PID %d) killed." % pid)
381 finally:
382 pid_path.remove()
383 else:
384 self.ctx.err("DEVELOPMENT: You will have to kill processes by hand!")
385
386 try:
387 register("web", WebControl, HELP)
388 except NameError:
389 if __name__ == "__main__":
390 cli = CLI()
391 cli.register("web", WebControl, HELP)
392 cli.invoke(sys.argv[1:])
393