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