1
2
3 """
4 :author: Josh Moore, josh at glencoesoftware.com
5
6 OMERO Grid admin controller
7
8 This is a python wrapper around icegridregistry/icegridnode for master
9 and various other tools needed for administration.
10
11 Copyright 2008 Glencoe Software, Inc. All Rights Reserved.
12 Use is subject to license terms supplied in LICENSE.txt
13
14 """
15
16 import re
17 import os
18 import sys
19 import stat
20 import platform
21 import portalocker
22
23 from path import path
24
25 import omero
26 import omero.config
27
28 from omero.cli import CLI
29 from omero.cli import BaseControl
30 from omero.cli import DirectoryType
31 from omero.cli import NonZeroReturnCode
32 from omero.cli import VERSION
33
34 from omero.plugins.prefs import with_config
35
36 from omero_ext.which import whichall
37 from omero_version import ice_compatibility
38
39 try:
40 import pywintypes
41 import win32service
42 import win32evtlogutil
43 import win32api
44 import win32security
45 has_win32 = True
46 except ImportError:
47 has_win32 = False
48
49 DEFAULT_WAIT = 300
50
51 HELP = """Administrative tools including starting/stopping OMERO.
52
53 Environment variables:
54 OMERO_MASTER
55 OMERO_NODE
56
57 Configuration properties:
58 omero.windows.user
59 omero.windows.pass
60
61 """ + "\n" + "="*50 + "\n"
65
66 - def _complete(self, text, line, begidx, endidx):
67 """
68 Returns a file after "deploy", "start", or "startasync"
69 and otherwise delegates to the BaseControl
70 """
71 for s in (" deploy ", " start ", " startasync "):
72 l = len(s)
73 i = line.find(s)
74 if i >= 0:
75 f = line[i+l:]
76 return self._complete_file(f)
77 return BaseControl._complete(self, text, line, begidx, endidx)
78
93
94 Action(
95 "start",
96 """Start icegridnode daemon and waits for required components to \
97 come up, i.e. status == 0
98
99 If the first argument can be found as a file, it will be deployed as the
100 application descriptor rather than etc/grid/default.xml. All other arguments
101 will be used as targets to enable optional sections of the descriptor""",
102 wait=True)
103
104 Action("startasync", "The same as start but returns immediately",)
105
106 Action("restart", "stop && start", wait=True)
107
108 Action(
109 "restartasync", """The same as restart but returns as soon as \
110 starting has begun.""",
111 wait=True)
112
113 Action("status", """Status of server
114
115 Returns with 0 status if a node ping is successful and if some SessionManager
116 returns an OMERO-specific exception on a bad login. This can be used in shell
117 scripts, e.g.:
118
119 $ omero admin status && echo "server started"
120 """)
121
122 Action(
123 "stop",
124 """Initiates node shutdown and waits for status to return a \
125 non-0 value""",
126 wait=True)
127
128 Action("stopasync", "The same as stop but returns immediately")
129
130 Action(
131 "deploy",
132 """Deploy the given deployment descriptor. See etc/grid/*.xml
133
134 If the first argument is not a file path, etc/grid/default.xml will be
135 deployed by default. Same functionality as start, but requires that the node
136 already be running. This may automatically restart some server components.""")
137
138 Action(
139 "ice", "Drop user into icegridadmin console or execute arguments")
140
141 fixpyramids = Action(
142 "fixpyramids", "Remove empty pyramid pixels files").parser
143
144
145 Action(
146 "diagnostics",
147 "Run a set of checks on the current, preferably active server")
148
149 Action(
150 "waitup",
151 "Used by start after calling startasync to wait on status==0",
152 wait=True)
153
154 Action(
155 "waitdown",
156 "Used by stop after calling stopasync to wait on status!=0",
157 wait=True)
158
159 reindex = Action(
160 "reindex",
161 """Re-index the Lucene index
162
163 Command-line tool for re-index the database. This command must be run on the
164 machine where /OMERO/FullText is located.
165
166 Examples:
167 bin/omero admin reindex --full \
168 # All objects
169 bin/omero admin reindex --class ome.model.core.Image \
170 # Only images
171 JAVA_OPTS="-Dlog4j.configuration=stderr.xml" bin/omero admin reindex --full\
172 # Passing arguments to Java
173
174
175 LIMITATION: omero.db.pass values do not currently get passed to the Java
176 process. You will need to all passwordless login to PostgreSQL. In
177 fact, only the following properties are passed:
178
179 omero.data.dir
180 omero.search.*
181 omero.db.* (excluding pass)
182
183 """).parser
184 reindex.add_argument(
185 "--jdwp", help="Activate remote debugging")
186 group = reindex.add_mutually_exclusive_group()
187 group.add_argument(
188 "--full", action="store_true",
189 help="Reindexes all non-excluded tables sequentially")
190 group.add_argument(
191 "--events", action="store_true",
192 help="Reindexes all non-excluded event logs chronologically")
193 group.add_argument(
194 "--class", nargs="+",
195 help="Reindexes the given classes sequentially")
196
197 ports = Action(
198 "ports",
199 """Allows modifying the ports from a standard OMERO install
200
201 To have two OMERO's running on the same machine, several ports must be
202 modified from their default values.
203 Internally, this command uses the omero.install.change_ports module.
204 Changing the ports on a running server is usually not what you want and
205 will be prevented. Use --skipcheck to change the ports anyway.
206
207 Examples:
208
209 %(prog)s --prefix=1 # sets ports to: 14061, \
210 14063, 14064
211 %(prog)s --prefix=1 --revert # sets ports back to: \
212 4061, 4063, 4064
213 %(prog)s --registry=4444 --tcp=5555 --ssl=6666 # sets ports to: 4444 \
214 5555 6666
215
216 """).parser
217 ports.add_argument(
218 "--prefix",
219 help="Adds a prefix to each port ON TOP OF any other settings")
220 ports.add_argument(
221 "--registry", default="4061",
222 help="Registry port. (default: %(default)s)")
223 ports.add_argument(
224 "--tcp", default="4063",
225 help="The tcp port to be used by Glacier2 (default: %(default)s)")
226 ports.add_argument(
227 "--ssl", default="4064",
228 help="The ssl port to be used by Glacier2 (default: %(default)s)")
229 ports.add_argument(
230 "--revert", action="store_true",
231 help="Used to rollback from the given settings to the defaults")
232 ports.add_argument(
233 "--skipcheck", action="store_true",
234 help="Skips the check if the server is already running")
235
236 sessionlist = Action(
237 "sessionlist", "List currently running sessions").parser
238 sessionlist.add_login_arguments()
239
240 cleanse = Action("cleanse", """Remove binary data files from OMERO
241
242 Deleting an object from OMERO currently does not remove the binary data. Use
243 this command either manually or in a cron job periodically to remove Pixels
244 and other data.
245
246 This is done by checking that for all the files in the given directory, a
247 matching entry exists on the server. THE /OMERO DIRECTORY MUST MATCH THE
248 DATABASE YOU ARE RUNNING AGAINST.
249
250 This command must be run on the machine where, for example, /OMERO/ is
251 located.
252
253 Examples:
254 bin/omero admin cleanse --dry-run /OMERO # Lists files that will be \
255 deleted
256 bin/omero admin cleanse /OMERO # Actually delete them.
257 bin/omero admin cleanse /volumes/data/OMERO # Delete from a standard \
258 location.
259
260 """).parser
261
262 for x in (cleanse, fixpyramids):
263 x.add_argument(
264 "--dry-run", action="store_true",
265 help="Print out which files would be deleted")
266 x.add_argument(
267 "data_dir", type=DirectoryType(),
268 help="omero.data.dir directory value (e.g. /OMERO")
269 x.add_login_arguments()
270
271 Action("checkwindows", "Run simple check of the local installation "
272 "(Windows-only)")
273 Action("checkice", "Run simple check of the Ice installation")
274
275 Action("events", "Print event log (Windows-only)")
276
277 self.actions["ice"].add_argument(
278 "argument", nargs="*",
279 help="""Arguments joined together to make an Ice command. If not \
280 present, the user will enter a console""")
281
282 self.actions["status"].add_argument(
283 "node", nargs="?", default="master")
284 self.actions["status"].add_argument(
285 "--nodeonly", action="store_true",
286 help="If set, then only tests if the icegridnode is running")
287
288 for name in ("start", "startasync"):
289 self.actions[name].add_argument(
290 "-u", "--user",
291 help="Service Log On As user name. If none given, the value"
292 " of omero.windows.user will be used. (Windows-only)")
293 self.actions[name].add_argument(
294 "-w", "--password",
295 help="Service Log On As user password. If none given, the"
296 " value of omero.windows.pass will be used. (Windows-only)")
297
298 for k in ("start", "startasync", "deploy", "restart", "restartasync"):
299 self.actions[k].add_argument(
300 "file", nargs="?",
301 help="Application descriptor. If not provided, a default"
302 " will be used")
303 self.actions[k].add_argument(
304 "targets", nargs="*",
305 help="Targets within the application descriptor which "
306 " should be activated. Common values are: \"debug\", "
307 "\"trace\" ")
308
309
310
311
312
313
314
315
316
317
318
319
320 if has_win32:
322 hscm = win32service.OpenSCManager(
323 None, None, win32service.SC_MANAGER_ALL_ACCESS)
324 try:
325 try:
326 hs = win32service.OpenService(
327 hscm, svc_name, win32service.SERVICE_ALL_ACCESS)
328 except:
329 return "DOESNOTEXIST"
330 try:
331 q = win32service.QueryServiceStatus(hs)
332 type, state, ctrl, err, svcerr, svccp, svcwh = q
333 if state == win32service.SERVICE_STOPPED:
334 return "STOPPED"
335 else:
336 return "unknown"
337 finally:
338 win32service.CloseServiceHandle(hs)
339 finally:
340 win32service.CloseServiceHandle(hscm)
341
343 def DumpRecord(record):
344 if str(record.SourceName) == svc_name:
345 self.ctx.out("Time: %s" % record.TimeWritten)
346 self.ctx.out("Rec: %s" % record.RecordNumber)
347 for si in record.StringInserts:
348 self.ctx.out(si)
349 self.ctx.out("="*20)
350 win32evtlogutil.FeedEventLogRecords(DumpRecord)
351
352 else:
353
355 self.ctx.die(
356 666, "Could not import win32service and/or win32evtlogutil")
357
359 self.ctx.die(
360 666, "Could not import win32service and/or win32evtlogutil")
361
362
363
364
365
366 - def _node(self, omero_node=None):
367 """
368 Overrides the regular node() logic to return the value of
369 OMERO_MASTER or "master"
370 """
371 if omero_node is not None:
372 os.environ["OMERO_MASTER"] = omero_node
373
374 if "OMERO_MASTER" in os.environ:
375 return os.environ["OMERO_MASTER"]
376 else:
377 return "master"
378
379 - def _cmd(self, *command_arguments):
380 """
381 Used to generate an icegridadmin command line argument list
382 """
383 command = ["icegridadmin", self._intcfg()]
384 command.extend(command_arguments)
385 return command
386
388 if args.file is not None:
389
390 descript = path(args.file).abspath()
391 if not descript.exists():
392 self.ctx.dbg("No such file: %s -- Using as target" % descript)
393 args.targets.insert(0, args.file)
394 descript = None
395 else:
396 descript = None
397
398 if descript is None:
399 __d__ = "default.xml"
400 if self._isWindows():
401 __d__ = "windefault.xml"
402 descript = self.ctx.dir / "etc" / "grid" / __d__
403 self.ctx.err("No descriptor given. Using %s"
404 % os.path.sep.join(["etc", "grid", __d__]))
405 return descript
406
408 """
409 Checks that the templates file as defined in etc\Windows.cfg
410 can be found.
411 """
412 self.check_access(os.R_OK)
413 if not self._isWindows():
414 self.ctx.die(123, "Not Windows")
415
416 import Ice
417 key = "IceGrid.Node.Data"
418 properties = Ice.createProperties([self._icecfg()])
419 nodedata = properties.getProperty(key)
420 if not nodedata:
421 self.ctx.die(300,
422 "Bad configuration: No IceGrid.Node.Data property")
423 nodepath = path(nodedata)
424 pp = nodepath.parpath(self.ctx.dir)
425 if pp:
426 return
427 if nodepath == r"c:\omero_dist\var\master":
428 self.ctx.out("Found default value: %s" % nodepath)
429 self.ctx.out("Attempting to correct...")
430 from omero.install.win_set_path import win_set_path
431 count = win_set_path(dir=self.ctx.dir)
432 if count:
433 return
434 self.ctx.die(400, """
435
436 %s is not in this directory. Aborting...
437
438 Please see the installation instructions on modifying
439 the files for your installation (%s)
440 with bin\winconfig.bat
441
442 """ % (nodedata, self.ctx.dir))
443
444
445
446
447
448
449 @with_config
451 """
452 First checks for a valid installation, then checks the grid,
453 then registers the action: "node HOST start"
454 """
455
456 self.check_access(config=config)
457 self.checkice()
458 self.check_node(args)
459 if self._isWindows():
460 self.checkwindows(args)
461
462 if 0 == self.status(args, node_only=True):
463 self.ctx.die(876, "Server already running")
464
465 self._initDir()
466
467 self._regdata()
468 self.check([])
469
470 user = args.user
471 pasw = args.password
472 descript = self._descript(args)
473
474 if self._isWindows():
475 svc_name = "OMERO.%s" % args.node
476 output = self._query_service(svc_name)
477
478
479 if 0 <= output.find("DOESNOTEXIST"):
480 binpath = """icegridnode.exe "%s" --deploy "%s" --service\
481 %s""" % (self._icecfg(), descript, svc_name)
482
483
484 if not user:
485 try:
486 user = config.as_map()["omero.windows.user"]
487 except KeyError:
488 user = None
489 if user is not None and len(user) > 0:
490 if "\\" not in user:
491 computername = win32api.GetComputerName()
492 user = "\\".join([computername, user])
493 try:
494
495
496 self.ctx.out("Granting SeServiceLogonRight to service"
497 " user \"%s\"" % user)
498 policy_handle = win32security.LsaOpenPolicy(
499 None, win32security.POLICY_ALL_ACCESS)
500 sid_obj, domain, tmp = \
501 win32security.LookupAccountName(None, user)
502 win32security.LsaAddAccountRights(
503 policy_handle, sid_obj, ('SeServiceLogonRight',))
504 win32security.LsaClose(policy_handle)
505 except pywintypes.error, details:
506 self.ctx.die(200, "Error during service user set up:"
507 " (%s) %s" % (details[0], details[2]))
508 if not pasw:
509 try:
510 pasw = config.as_map()["omero.windows.pass"]
511 except KeyError:
512 pasw = self._ask_for_password(
513 " for service user \"%s\"" % user)
514 else:
515 pasw = None
516
517 hscm = win32service.OpenSCManager(
518 None, None, win32service.SC_MANAGER_ALL_ACCESS)
519 try:
520 self.ctx.out("Installing %s Windows service." % svc_name)
521 hs = win32service.CreateService(
522 hscm, svc_name, svc_name,
523 win32service.SERVICE_ALL_ACCESS,
524 win32service.SERVICE_WIN32_OWN_PROCESS,
525 win32service.SERVICE_AUTO_START,
526 win32service.SERVICE_ERROR_NORMAL, binpath, None, 0,
527 None, user, pasw)
528 self.ctx.out("Successfully installed %s Windows service."
529 % svc_name)
530 win32service.CloseServiceHandle(hs)
531 finally:
532 win32service.CloseServiceHandle(hscm)
533
534
535 if 0 <= output.find("RUNNING"):
536 self.ctx.die(201, "%s is already running. Use stop first"
537 % svc_name)
538
539
540 hscm = win32service.OpenSCManager(
541 None, None, win32service.SC_MANAGER_ALL_ACCESS)
542 try:
543 try:
544 hs = win32service.OpenService(
545 hscm, svc_name, win32service.SC_MANAGER_ALL_ACCESS)
546 win32service.StartService(hs, None)
547 self.ctx.out("Starting %s Windows service." % svc_name)
548 except pywintypes.error, details:
549 self.ctx.out("%s service startup failed: (%s) %s"
550 % (svc_name, details[0], details[2]))
551 win32service.DeleteService(hs)
552 self.ctx.die(202, "%s service deleted." % svc_name)
553 finally:
554 win32service.CloseServiceHandle(hs)
555 win32service.CloseServiceHandle(hscm)
556
557 else:
558 command = [
559 "icegridnode", "--daemon", "--pidfile", str(self._pid()),
560 "--nochdir", self._icecfg(), "--deploy", str(descript)
561 ] + args.targets
562 self.ctx.rv = self.ctx.call(command)
563
564 @with_config
565 - def start(self, args, config):
576
577 @with_config
578 - def deploy(self, args, config):
579 self.check_access()
580 self.checkice()
581 descript = self._descript(args)
582
583
584
585
586 command = ["icegridadmin", self._intcfg(), "-e",
587 " ".join(["application", "update", str(descript)] +
588 args.targets)]
589 self.ctx.call(command)
590
591 - def status(self, args, node_only=False):
592 self.check_node(args)
593 command = self._cmd("-e", "node ping %s" % self._node())
594 self.ctx.rv = self.ctx.popen(command).wait()
595
596
597
598
599 if not node_only:
600 node_only = getattr(args, "nodeonly", False)
601
602 if self.ctx.rv == 0 and not node_only:
603 try:
604 import Ice
605 ic = Ice.initialize([self._intcfg()])
606 try:
607 sm = self.session_manager(ic)
608 try:
609 sm.create("####### STATUS CHECK ########", None)
610
611 except omero.WrappedCreateSessionException:
612
613 self.ctx.dbg("Server reachable")
614 self.ctx.rv = 0
615 finally:
616 ic.destroy()
617 except Exception, exc:
618 self.ctx.rv = 1
619 self.ctx.dbg("Server not reachable: "+str(exc))
620
621 return self.ctx.rv
622
624 """
625 Since the stop and start are separately protected by
626 the lock on config.xml, we need to wait for some time
627 to hopefully let the icegridnode process release the
628 file locks.
629 """
630 self.ctx.sleep(1)
631
632 @with_config
638
639 @with_config
645
647 """
648 Loops 30 times with 10 second pauses waiting for status()
649 to return 0. If it does not, then ctx.die() is called.
650 """
651 self.check_access(os.R_OK)
652 self.ctx.out("Waiting on startup. Use CTRL-C to exit")
653 count, loop_secs, time_msg = self.loops_and_wait(args)
654 while True:
655 count = count - 1
656 if count == 0:
657 self.ctx.die(43, "\nFailed to startup some components after"
658 " %s" % time_msg)
659 elif 0 == self.status(args, node_only=False):
660 break
661 else:
662 self.ctx.out(".", newline=False)
663 self.ctx.sleep(loop_secs)
664
666 """
667 Returns true if the server went down
668 """
669 self.check_access(os.R_OK)
670 self.ctx.out("Waiting on shutdown. Use CTRL-C to exit")
671 count, loop_secs, time_msg = self.loops_and_wait(args)
672 while True:
673 count = count - 1
674 if count == 0:
675 self.ctx.die(44, "\nFailed to shutdown some components after"
676 " %s" % time_msg)
677 return False
678 elif 0 != self.status(args, node_only=True):
679 break
680 else:
681 self.ctx.out(".", newline=False)
682 self.ctx.sleep(loop_secs)
683 self.ctx.rv = 0
684 return True
685
687 """
688 If present, get the wait time from the args argument
689 and calculate the number of loops and the wait time
690 needed. If not present in args, use a default value.
691 """
692
693 if not hasattr(args, "wait"):
694
695
696
697 args.wait = DEFAULT_WAIT
698
699 total_secs = args.wait
700 loop_secs = total_secs / 30.0
701 return 30, loop_secs, "%s seconds" % total_secs
702
703 @with_config
705 """
706 Returns true if the server was already stopped
707 """
708 self.check_node(args)
709 if 0 != self.status(args, node_only=True):
710 self.ctx.err("Server not running")
711 return True
712 elif self._isWindows():
713 svc_name = "OMERO.%s" % args.node
714 output = self._query_service(svc_name)
715 if 0 <= output.find("DOESNOTEXIST"):
716 self.ctx.die(203, "%s does not exist. Use 'start' first."
717 % svc_name)
718 hscm = win32service.OpenSCManager(
719 None, None, win32service.SC_MANAGER_ALL_ACCESS)
720 try:
721 hs = win32service.OpenService(
722 hscm, svc_name, win32service.SC_MANAGER_ALL_ACCESS)
723 win32service.ControlService(
724 hs, win32service.SERVICE_CONTROL_STOP)
725 win32service.DeleteService(hs)
726 self.ctx.out("%s service deleted." % svc_name)
727 finally:
728 win32service.CloseServiceHandle(hs)
729 win32service.CloseServiceHandle(hscm)
730 else:
731 command = self._cmd("-e", "node shutdown %s" % self._node())
732 try:
733 self.ctx.call(command)
734 except NonZeroReturnCode, nzrc:
735 self.ctx.rv = nzrc.rv
736 self.ctx.out("Was the server already stopped?")
737
738 @with_config
739 - def stop(self, args, config):
743
747
748 - def ice(self, args):
749 self.check_access()
750 command = self._cmd()
751 if len(args.argument) > 0:
752 command.extend(["-e", " ".join(args.argument)])
753 return self.ctx.call(command)
754 else:
755 self.ctx.call(command)
756
757 @with_config
766
767 @with_config
769 self.check_access()
770 config = config.as_map()
771 omero_data_dir = '/OMERO'
772 try:
773 omero_data_dir = config['omero.data.dir']
774 except KeyError:
775 pass
776
777 from omero.util.temp_files import gettempdir
778
779
780
781 omero_temp_dir = gettempdir()
782 omero_temp_dir = os.path.abspath(
783 os.path.join(omero_temp_dir, os.path.pardir, os.path.pardir))
784
785 self.ctx.out("""
786 %s
787 OMERO Diagnostics %s
788 %s
789 """ % ("="*80, VERSION, "="*80))
790
791 def sz_str(sz):
792 for x in ["KB", "MB", "GB"]:
793 sz /= 1000
794 if sz < 1000:
795 break
796 sz = "%.1f %s" % (sz, x)
797 return sz
798
799 def item(cat, msg):
800 cat = cat + ":"
801 cat = "%-12s" % cat
802 self.ctx.out(cat, False)
803 msg = "%-30s " % msg
804 self.ctx.out(msg, False)
805
806 def exists(p):
807 if p.isdir():
808 if not p.exists():
809 self.ctx.out("doesn't exist")
810 else:
811 self.ctx.out("exists")
812 else:
813 if not p.exists():
814 self.ctx.out("n/a")
815 else:
816 warn = 0
817 err = 0
818 for l in p.lines():
819
820 lcl = l.lower()
821 found_err = lcl.find("error") >= 0
822 found_warn = lcl.find("warn") >= 0
823
824 if found_err:
825 err += 1
826 elif found_warn:
827 warn += 1
828 msg = ""
829 if warn or err:
830 msg = " errors=%-4s warnings=%-4s" % (err, warn)
831 self.ctx.out("%-12s %s" % (sz_str(p.size), msg))
832
833 def version(cmd):
834 """
835 Returns a true response only
836 if a valid version was found.
837 """
838 item("Commands", "%s" % " ".join(cmd))
839 try:
840 p = self.ctx.popen(cmd)
841 except OSError:
842 self.ctx.err("not found")
843 return False
844
845 p.wait()
846 io = p.communicate()
847 try:
848 v = io[0].split()
849 v.extend(io[1].split())
850 v = "".join(v)
851 m = re.match("^\D*(\d[.\d]+\d)\D?.*$", v)
852 v = "%-10s" % m.group(1)
853 self.ctx.out(v, False)
854 try:
855 where = whichall(cmd[0])
856 sz = len(where)
857 if sz == 0:
858 where = "unknown"
859 else:
860 where = where[0]
861 if sz > 1:
862 where += " -- %s others" % sz
863
864 except:
865 where = "unknown"
866 self.ctx.out("(%s)" % where)
867 return True
868 except Exception, e:
869 self.ctx.err("error:%s" % e)
870 return False
871
872 import logging
873 logging.basicConfig()
874 from omero.util.upgrade_check import UpgradeCheck
875 check = UpgradeCheck("diagnostics")
876 check.run()
877 if check.isUpgradeNeeded():
878 self.ctx.out("")
879
880 version(["java", "-version"])
881 version(["python", "-V"])
882 version(["icegridnode", "--version"])
883 iga = version(["icegridadmin", "--version"])
884 version(["psql", "--version"])
885
886 def get_ports(input):
887 router_lines = [line for line in input.split("\n")
888 if line.find("ROUTER") >= 0]
889
890 ssl_port = None
891 tcp_port = None
892 for line in router_lines:
893 if not ssl_port and line.find("ROUTERPORT") >= 0:
894 m = re.match(".*?(\d+).*?$", line)
895 if m:
896 ssl_port = m.group(1)
897
898 if not tcp_port and line.find("INSECUREROUTER") >= 0:
899 m = re.match("^.*?-p (\d+).*?$", line)
900 if m:
901 tcp_port = m.group(1)
902 return ssl_port, tcp_port
903
904 self.ctx.out("")
905 if not iga:
906 self.ctx.out(
907 "No icegridadmin available: Cannot check server list")
908 else:
909 item("Server", "icegridnode")
910 p = self.ctx.popen(self._cmd("-e", "server list"))
911 rv = p.wait()
912 io = p.communicate()
913 if rv != 0:
914 self.ctx.out("not started")
915 self.ctx.dbg("""
916 Stdout:\n%s
917 Stderr:\n%s
918 """ % io)
919 else:
920 self.ctx.out("running")
921 servers = io[0].split()
922 servers.sort()
923 for s in servers:
924 item("Server", "%s" % s)
925 p2 = self.ctx.popen(
926 self._cmd("-e", "server state %s" % s))
927 p2.wait()
928 io2 = p2.communicate()
929 if io2[1]:
930 self.ctx.err(io2[1].strip())
931 elif io2[0]:
932 self.ctx.out(io2[0].strip())
933 else:
934 self.ctx.err("UNKNOWN!")
935 if self._isWindows():
936
937 hscm = win32service.OpenSCManager(
938 None, None, win32service.SC_MANAGER_ALL_ACCESS)
939 services = win32service.EnumServicesStatus(hscm)
940 omesvcs = tuple((sname, fname) for sname, fname, status
941 in services if "OMERO" in fname)
942 for sname, fname in omesvcs:
943 item("Server", fname)
944 hsc = win32service.OpenService(
945 hscm, sname, win32service.SC_MANAGER_ALL_ACCESS)
946 logonuser = win32service.QueryServiceConfig(hsc)[7]
947 if win32service.QueryServiceStatus(hsc)[1] == \
948 win32service.SERVICE_RUNNING:
949 self.ctx.out("active (running as %s)" % logonuser)
950 else:
951 self.ctx.out("inactive")
952 win32service.CloseServiceHandle(hsc)
953 win32service.CloseServiceHandle(hscm)
954
955
956 self.ctx.out("")
957 p = self.ctx.popen(self._cmd("-e", "application list"))
958 rv = p.wait()
959 io = p.communicate()
960 if rv != 0:
961 self.ctx.out("Cannot list deployed applications.")
962 self.ctx.dbg("""
963 Stdout:\n%s
964 Stderr:\n%s
965 """ % io)
966 else:
967 applications = io[0].split()
968 applications.sort()
969 for s in applications:
970 p2 = self.ctx.popen(
971 self._cmd("-e", "application describe %s" % s))
972 io2 = p2.communicate()
973 if io2[1]:
974 self.ctx.err(io2[1].strip())
975 elif io2[0]:
976 ssl_port, tcp_port = get_ports(io2[0])
977 item("%s" % s, "SSL port")
978 if not ssl_port:
979 self.ctx.err("Not found")
980 else:
981 self.ctx.out("%s" % ssl_port)
982
983 item("%s" % s, "TCP port")
984 if not tcp_port:
985 self.ctx.err("Not found")
986 else:
987 self.ctx.out("%s" % tcp_port)
988 else:
989 self.ctx.err("UNKNOWN!")
990
991 def log_dir(log, cat, cat2, knownfiles):
992 self.ctx.out("")
993 item(cat, "%s" % log.abspath())
994 exists(log)
995 self.ctx.out("")
996
997 if log.exists():
998 files = log.files()
999 files = set([x.basename() for x in files])
1000
1001 for x in knownfiles:
1002 files.add(x)
1003 files = list(files)
1004 files.sort()
1005 for x in files:
1006 item(cat2, x)
1007 exists(log / x)
1008 item(cat2, "Total size")
1009 sz = 0
1010 for x in log.walkfiles():
1011 sz += x.size
1012 self.ctx.out("%-.2f MB" % (float(sz)/1000000.0))
1013
1014 log_dir(self.ctx.dir / "var" / "log", "Log dir", "Log files",
1015 ["Blitz-0.log", "Tables-0.log", "Processor-0.log",
1016 "Indexer-0.log", "FileServer.log", "MonitorServer.log",
1017 "DropBox.log", "TestDropBox.log", "OMEROweb.log"])
1018
1019
1020 self.ctx.out("")
1021 ready = re.compile(".*?ome.services.util.ServerVersionCheck\
1022 .*OMERO.Version.*Ready..*?")
1023 db_ready = re.compile(".*?Did.you.create.your.database[?].*?")
1024 data_dir = re.compile(".*?Unable.to.initialize:.FullText.*?")
1025 pg_password = re.compile(".*?org.postgresql.util.PSQLException:\
1026 .FATAL:.password.*?authentication.failed.for.user.*?")
1027 pg_user = re.compile(""".*?org.postgresql.util.PSQLException:\
1028 .FATAL:.role.".*?".does.not.exist.*?""")
1029 pg_conn = re.compile(""".*?org.postgresql.util.PSQLException:\
1030 .Connection.refused.""")
1031
1032 issues = {
1033 ready: "=> Server restarted <=",
1034 db_ready: "Your database configuration is invalid",
1035 data_dir: "Did you create your omero.data.dir? E.g. /OMERO",
1036 pg_password: "Your postgres password seems to be invalid",
1037 pg_user: "Your postgres user is invalid",
1038 pg_conn: "Your postgres hostname and/or port is invalid"
1039 }
1040
1041 try:
1042 for file in ('Blitz-0.log',):
1043
1044 p = self.ctx.dir / "var" / "log" / file
1045 import fileinput
1046 for line in fileinput.input([str(p)]):
1047 lno = fileinput.filelineno()
1048 for k, v in issues.items():
1049 if k.match(line):
1050 item('Parsing %s' % file, "[line:%s] %s"
1051 % (lno, v))
1052 self.ctx.out("")
1053 break
1054 except:
1055 self.ctx.err("Error while parsing logs")
1056
1057 self.ctx.out("")
1058
1059 def env_val(val):
1060 item("Environment", "%s=%s"
1061 % (val, os.environ.get(val, "(unset)")))
1062 self.ctx.out("")
1063 env_val("OMERO_HOME")
1064 env_val("OMERO_NODE")
1065 env_val("OMERO_MASTER")
1066 env_val("OMERO_TEMPDIR")
1067 env_val("PATH")
1068 env_val("ICE_HOME")
1069 env_val("LD_LIBRARY_PATH")
1070 env_val("DYLD_LIBRARY_PATH")
1071
1072 self.ctx.out("")
1073 for dir_name, dir_path, dir_size in (
1074 ("data", omero_data_dir, ""),
1075 ("temp", omero_temp_dir, True)):
1076 dir_path_exists = os.path.exists(dir_path)
1077 is_writable = os.access(dir_path, os.R_OK | os.W_OK)
1078 if dir_size and dir_path_exists:
1079 dir_size = self.getdirsize(omero_temp_dir)
1080 dir_size = " (Size: %s)" % dir_size
1081 self.ctx.out("OMERO %s dir: '%s'\tExists? %s\tIs writable? %s%s" %
1082 (dir_name, dir_path, dir_path_exists, is_writable,
1083 dir_size))
1084
1085 from omero.plugins.web import WebControl
1086 try:
1087 WebControl().status(args)
1088 except:
1089 self.ctx.out("OMERO.web not installed!")
1090
1097
1099 import IceGrid
1100 import Glacier2
1101 iq = communicator.stringToProxy("IceGrid/Query")
1102 iq = IceGrid.QueryPrx.checkedCast(iq)
1103 sm = iq.findAllObjectsByType("::Glacier2::SessionManager")[0]
1104 sm = Glacier2.SessionManagerPrx.checkedCast(sm)
1105 return sm
1106
1107 - def can_access(self, filepath, mask=os.R_OK | os.W_OK):
1108 """
1109 Check that the given path belongs to
1110 or is accessible by the current user
1111 on Linux systems.
1112 """
1113
1114 if "Windows" == platform.system():
1115 return
1116
1117 pathobj = path(filepath)
1118
1119 if not pathobj.exists():
1120 self.ctx.die(8, "FATAL: OMERO directory does not exist: %s"
1121 % pathobj)
1122
1123 owner = os.stat(filepath)[stat.ST_UID]
1124 if owner == 0:
1125 msg = ""
1126 msg += "FATAL: OMERO directory which needs to be writeable"\
1127 " belongs to root: %s\n" % filepath
1128 msg += "Please use \"chown -R NEWUSER %s\" and run as then"\
1129 " run %s as NEWUSER" % (filepath, sys.argv[0])
1130 self.ctx.die(9, msg)
1131 else:
1132 if not os.access(filepath, mask):
1133 self.ctx.die(10, "FATAL: Cannot access %s, a required"
1134 " file/directory for OMERO" % filepath)
1135
1136 - def check_access(self, mask=os.R_OK | os.W_OK, config=None):
1137 """Check that 'var' is accessible by the current user."""
1138
1139 var = self.ctx.dir / 'var'
1140 if not os.path.exists(var):
1141 self.ctx.out("Creating directory %s" % var)
1142 os.makedirs(var, 0700)
1143 else:
1144 self.can_access(var, mask)
1145
1146 if config is not None:
1147 omero_data_dir = '/OMERO'
1148 config = config.as_map()
1149 try:
1150 omero_data_dir = config['omero.data.dir']
1151 except KeyError:
1152 pass
1153 self.can_access(omero_data_dir)
1154 for p in os.listdir(var):
1155 subpath = os.path.join(var, p)
1156 if os.path.isdir(subpath):
1157 self.can_access(subpath, mask)
1158
1160 """
1161 If the args argparse.Namespace argument has no "node" attribute,
1162 then assign one.
1163 """
1164 if not hasattr(args, "node"):
1165 args.node = self._node()
1166
1168 """
1169 Checks for Ice version 3.4
1170
1171 See ticket:2514, ticket:1260
1172 """
1173
1174 def _check(msg, vers):
1175 compat = ice_compatibility.split(".")
1176 vers = vers.split(".")
1177 if compat[0:2] != vers[0:2]:
1178 self.ctx.die(164, "%s is not compatible with %s: %s"
1179 % (msg, ".".join(compat), ".".join(vers)))
1180
1181 import Ice
1182 vers = Ice.stringVersion()
1183 _check("IcePy version", vers)
1184
1185 popen = self.ctx.popen(["icegridnode", "--version"])
1186 vers = popen.communicate()[1]
1187 _check("icegridnode version", vers)
1188
1190 """
1191 Callers are responsible for closing the
1192 returned ConfigXml object.
1193 """
1194 cfg_xml = self.ctx.dir / "etc" / "grid" / "config.xml"
1195 cfg_tmp = self.ctx.dir / "etc" / "grid" / "config.xml.tmp"
1196 grid_dir = self.ctx.dir / "etc" / "grid"
1197 if not cfg_xml.exists() and self.can_access(grid_dir):
1198 if cfg_tmp.exists() and self.can_access(cfg_tmp):
1199 self.ctx.dbg("Removing old config.xml.tmp")
1200 cfg_tmp.remove()
1201 config = omero.config.ConfigXml(str(cfg_tmp))
1202 try:
1203 self.ctx.controls["config"].upgrade(None, config)
1204 finally:
1205 config.close()
1206 self.ctx.err("Creating %s" % cfg_xml)
1207 cfg_tmp.rename(str(cfg_xml))
1208
1209 try:
1210 try:
1211 config = omero.config.ConfigXml(str(cfg_xml))
1212 except Exception, e:
1213 self.ctx.die(577, str(e))
1214 if config.save_on_close:
1215 config.save()
1216 else:
1217 self.ctx.err("%s read-only" % cfg_xml)
1218 except portalocker.LockException:
1219 try:
1220 config.close()
1221 except:
1222 pass
1223 self.ctx.die(111, "Could not acquire lock on %s" % cfg_xml)
1224
1225 return config
1226
1227 @with_config
1229 self.check_access(config=config)
1230 import omero.java
1231 server_dir = self.ctx.dir / "lib" / "server"
1232 log4j = "-Dlog4j.configuration=log4j-cli.properties"
1233 classpath = [file.abspath() for file in server_dir.files("*.jar")]
1234 xargs = [log4j, "-Xmx1024M", "-cp", os.pathsep.join(classpath)]
1235
1236 cfg = config.as_map()
1237 config.close()
1238 for x in ("name", "user", "host", "port"):
1239
1240 k = "omero.db.%s" % x
1241 if k in cfg:
1242 v = cfg[k]
1243 xargs.append("-D%s=%s" % (k, v))
1244 if "omero.data.dir" in cfg:
1245 xargs.append("-Domero.data.dir=%s" % cfg["omero.data.dir"])
1246 for k, v in cfg.items():
1247 if k.startswith("omero.search"):
1248 xargs.append("-D%s=%s" % (k, cfg[k]))
1249
1250 cmd = ["ome.services.fulltext.Main"]
1251
1252 if args.full:
1253 cmd.append("full")
1254 elif args.events:
1255 cmd.append("events")
1256 elif getattr(args, "class"):
1257 cmd.append("reindex")
1258 cmd.extend(getattr(args, "class"))
1259 else:
1260 self.ctx.die(502, "No valid action: %s" % args)
1261
1262 debug = False
1263 if getattr(args, "jdwp"):
1264 debug = True
1265
1266 self.ctx.dbg(
1267 "Launching Java: %s, debug=%s, xargs=%s" % (cmd, debug, xargs))
1268 p = omero.java.popen(
1269 cmd, debug=debug, xargs=xargs, stdout=sys.stdout,
1270 stderr=sys.stderr)
1271 self.ctx.rv = p.wait()
1272
1274 self.check_access()
1275 from omero.install.change_ports import change_ports
1276 if not args.skipcheck:
1277 if 0 == self.status(args, node_only=True):
1278 self.ctx.die(
1279 100, "Can't change ports while the server is running!")
1280
1281
1282 self.ctx.rv = 0
1283
1284 if args.prefix:
1285 for x in ("registry", "tcp", "ssl"):
1286 setattr(args, x, "%s%s" % (args.prefix, getattr(args, x)))
1287 change_ports(
1288 args.ssl, args.tcp, args.registry, args.revert, dir=self.ctx.dir)
1289
1297
1299 client = self.ctx.conn(args)
1300 service = client.sf.getQueryService()
1301 params = omero.sys.ParametersI()
1302 query = "select s from Session s join fetch s.node n join fetch"\
1303 " s.owner o where s.closed is null and n.id != 0"
1304 results = service.findAllByQuery(query, params)
1305 mapped = list()
1306 for s in results:
1307 rv = list()
1308 mapped.append(rv)
1309 if not s.isLoaded():
1310 rv.append("")
1311 rv.append("id=%s" % s.id.val)
1312 rv.append("")
1313 rv.append("")
1314 rv.append("")
1315 rv.append("insufficient privileges")
1316 else:
1317 rv.append(s.node.id)
1318 rv.append(s.uuid)
1319 rv.append(s.started)
1320 rv.append(s.owner.omeName)
1321 if s.userAgent is None:
1322 rv.append("")
1323 else:
1324 rv.append(s.userAgent)
1325 if client.getSessionId() == s.uuid.val:
1326 rv.append("current session")
1327 else:
1328 rv.append("")
1329 self.ctx.controls["hql"].display(
1330 mapped, ("node", "session", "started", "owner", "agent", "notes"))
1331 try:
1332 register("admin", AdminControl, HELP)
1333 except NameError:
1334 if __name__ == "__main__":
1335 cli = CLI()
1336 cli.register("admin", AdminControl, HELP)
1337 cli.invoke(sys.argv[1:])
1338