1
2 """
3 :author: Josh Moore, josh at glencoesoftware.com
4
5 OMERO Grid admin controller
6
7 This is a python wrapper around icegridregistry/icegridnode for master
8 and various other tools needed for administration.
9
10 Copyright 2008 Glencoe Software, Inc. All Rights Reserved.
11 Use is subject to license terms supplied in LICENSE.txt
12
13 """
14
15 import re
16 import os
17 import time
18 import exceptions
19
20 from path import path
21 from which import whichall
22
23 import omero
24 import omero_ServerErrors_ice
25 from omero.cli import Arguments
26 from omero.cli import BaseControl
27 from omero.cli import NonZeroReturnCode
28 from omero.cli import VERSION
29
30 try:
31 import win32service
32 import win32evtlogutil
33 has_win32 = True
34 except ImportError:
35 has_win32 = False
36
37
39
40 - def help(self, args = None):
41 self.ctx.out( """
42 Syntax: %(program_name)s admin [ start | update | stop | status ]
43
44 : No argument opens a command shell
45
46 Main Commands
47 -------------
48
49 start [filename] [targets] : Start icegridnode daemon and waits for required components
50 : to come up, i.e. status == 0
51 :
52 : If the first argument can be found as a file, it will
53 : be deployed as the application descriptor rather than
54 : etc/grid/default.xml. All other arguments will be used
55 : as targets to enable optional sections of the descriptor
56
57 startasync [filename] [targets] : The same as start but returns immediately.
58
59 deploy [filename] [targets] : Deploy the given deployment descriptor. See etc/grid/*.xml
60 : If the first argument is not a file path, etc/grid/default.xml
61 : will be deployed by default. Same functionality as start, but
62 : requires that the node already be running. This may automatically
63 : restart some server components.
64
65 stop : Initiates node shutdown and waits for status to return a non-0
66 : value
67
68 stopasync : The same as stop but returns immediately.
69
70 status : Status of server. Returns with 0 status if a node ping is successful
71 : and if some SessionManager returns an OMERO-specific exception on
72 : a bad login. This can be used in shell scripts, e.g.:
73 :
74 : omero admin status && echo "server started"
75 :
76
77 ice [arg1 arg2 ...] : Drop user into icegridadmin console or execute arguments
78
79
80 Other Commands
81 --------------
82
83 diagnostics : Run a set of checks on the current, preferably active server
84
85 waitup : Used by start after calling startasync to wait on status==0
86
87 waitdown : Used by stop after calling stopasync to wait on status!=0
88
89 events : Print event log (Windows-only)
90
91 """)
92 DISABLED = """ see: http://www.zeroc.com/forums/bug-reports/4237-sporadic-freeze-errors-concurrent-icegridnode-access.html
93 restart [filename] [targets] : Calls stop followed by start args
94 restartasync [filename] [targets] : Calls stop followed by startasync args
95 """
96
97
98
99
100 if has_win32:
102 hscm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
103 try:
104 try:
105 hs = win32service.OpenService(hscm, svc_name, win32service.SERVICE_ALL_ACCESS)
106 except:
107 return "DOESNOTEXIST"
108 try:
109 q = win32service.QueryServiceStatus(hs)
110 type, state, ctrl, err, svcerr, svccp, svcwh = q
111 if state == win32service.SERVICE_STOPPED:
112 return "STOPPED"
113 else:
114 return "unknown"
115 finally:
116 win32service.CloseServiceHandle(hs)
117 finally:
118 win32service.CloseServiceHandle(hscm)
119
121 def DumpRecord(record):
122 if str(record.SourceName) == svc_name:
123 self.ctx.out("Time: %s" % record.TimeWritten)
124 self.ctx.out("Rec: %s" % record.RecordNumber)
125 for si in record.StringInserts:
126 self.ctx.out(si)
127 self.ctx.out("="*20)
128 win32evtlogutil.FeedEventLogRecords(DumpRecord)
129
130 else:
131
133 self.ctx.die(666, "Could not import win32service and/or win32evtlogutil")
134
136 """
137 Query the service
138 Required to check the stdout since
139 rcode is not non-0
140 """
141 command = ["sc", "query", svc_name]
142 popen = self.ctx.popen(command)
143 output = popen.communicate()[0]
144 if 0 <= output.find("1060"):
145 return "DOESNOTEXIST"
146 else:
147 return output
148
149
150
151
152
153 - def _complete(self, text, line, begidx, endidx):
154 s = " deploy "
155 l = len(s)
156 i = line.find(s)
157 if i >= 0:
158 f = line[i+l:]
159 p = path(f)
160 if p.exists() and p.isdir():
161 if not f.endswith(os.sep):
162 return [p.basename()+os.sep]
163 return [ str(i)[len(f):] for i in p.listdir() ]
164 else:
165 results = [ str(i.basename()) for i in self.dir.glob(f+"*") ]
166 if len(results) == 1:
167
168 maybe_dir = path(results[0])
169 if maybe_dir.exists() and maybe_dir.isdir():
170 return [ results[0] + os.sep ]
171 return results
172 else:
173 return BaseControl._complete(self, text, line, begidx, endidx)
174
175 - def _node(self, omero_node = None):
176 """ Overrides the regular node() logic to return the value of OMERO_MASTER or "master" """
177 if omero_node != None:
178 os.environ["OMERO_MASTER"] = omero_node
179
180 if os.environ.has_key("OMERO_MASTER"):
181 return os.environ["OMERO_MASTER"]
182 else:
183 return "master"
184
185 - def _cmd(self, *args):
186 command = ["icegridadmin", self._intcfg() ]
187 command.extend(args)
188 return command
189
191 if first != None and len(first) > 0:
192
193 descript = path(first).abspath()
194 if not descript.exists():
195 self.ctx.dbg("No such file: %s -- Using as target" % descript)
196 other.insert(0, first)
197 descript = None
198 else:
199 descript = None
200
201 if descript == None:
202 __d__ = "default.xml"
203 if self._isWindows():
204 __d__ = "windefault.xml"
205 descript = self.dir / "etc" / "grid" / __d__
206 self.ctx.err("No descriptor given. Using %s" % os.path.sep.join(["etc","grid",__d__]))
207 return descript
208
210 """
211 Checks that the templates file as defined in etc\Windows.cfg
212 can be found.
213 """
214
215 if not self._isWindows():
216 self.ctx.die(123, "Not Windows")
217
218 args = Arguments(*args)
219 import Ice
220 key = "IceGrid.Node.Data"
221 properties = Ice.createProperties([self._icecfg()])
222 nodedata = properties.getProperty(key)
223 if not nodedata:
224 self.ctx.die(300, "Bad configuration: No IceGrid.Node.Data property")
225 nodepath = path(nodedata)
226 pp = nodepath.parpath(self.ctx.dir)
227 if pp:
228 return
229 if nodepath == r"c:\omero_dist\var\master":
230 self.ctx.out("Found default value: %s" % nodepath)
231 self.ctx.out("Attempting to correct...")
232 from omero.install.win_set_path import win_set_path
233 count = win_set_path()
234 if count:
235 return
236 self.ctx.die(400, """
237
238 %s is not in this directory. Aborting...
239
240 Please see the installation instructions on modifying
241 the files for your installation (%s)
242 with bin\winconfig.bat
243
244 """ % (nodedata, self.ctx.dir))
245
246
247
248
249
250
252 """
253 First checks for a valid installation, then checks the grid,
254 then registers the action: "node HOST start"
255 """
256
257 if self._isWindows():
258 self.checkwindows()
259
260
261
262
263 self._initDir()
264 props = self._properties()
265
266 self._regdata()
267 self.check([])
268
269 user = None
270 args = Arguments(args)
271 first, other = args.firstOther()
272 if first == "-u":
273 user = first
274 args = Arguments(other)
275 first, other = args.firstOther()
276 descript = self._descript(first, other)
277
278 if self._isWindows():
279 svc_name = "OMERO.%s" % self._node()
280 output = self._query_service(svc_name)
281
282
283 if 0 <= output.find("DOESNOTEXIST"):
284 command = [
285 "sc", "create", svc_name,
286 "binPath=","""icegridnode.exe "%s" --deploy "%s" --service %s""" % (self._icecfg(), descript, svc_name),
287 "DisplayName=", svc_name,
288 "start=","auto"]
289
290
291 if user:
292 user = self.ctx.input("User account:", False)
293 if not user:
294 user = self.ctx.initData().properties.getProperty("omero.windows.user")
295 if len(user) > 0:
296 command.append("obj=")
297 command.append(user)
298 self.ctx.out(self.ctx.popen(["ntrights","+r","SeServiceLogonRight","-u",user]).communicate()[0])
299 pasw = self.ctx.initData().properties.getProperty("omero.windows.pass")
300 pasw = self._ask_for_password(" for service user: %s" % user, pasw)
301 command.append("password=")
302 command.append(pasw)
303 self.ctx.out(self.ctx.popen(command).communicate()[0])
304
305
306 if 0 <= output.find("RUNNING"):
307 self.ctx.die(201, "%s is already running. Use stop first" % svc_name)
308
309
310 output = self.ctx.popen(["sc","start",svc_name]).communicate()[0]
311 self.ctx.out(output)
312 else:
313 command = ["icegridnode","--daemon","--pidfile",str(self._pid()),"--nochdir",self._icecfg(),"--deploy",str(descript)] + other
314 self.ctx.call(command)
315
319
321 args = Arguments(args)
322 first, other = args.firstOther()
323 descript = self._descript(first, other)
324
325
326 command = ["icegridadmin",self._intcfg(),"-e"," ".join(["application","update", str(descript)] + other)]
327 self.ctx.call(command)
328
330 args = Arguments(args)
331 first,other = args.firstOther()
332 if first == None:
333 first = "master"
334
335 command = self._cmd("-e","node ping %s" % first)
336 self.ctx.rv = self.ctx.popen(command).wait()
337
338 if self.ctx.rv == 0:
339 try:
340 import omero, Ice, IceGrid, Glacier2
341 ic = Ice.initialize([self._intcfg()])
342 try:
343 iq = ic.stringToProxy("IceGrid/Query")
344 iq = IceGrid.QueryPrx.checkedCast(iq)
345 sm = iq.findAllObjectsByType("::Glacier2::SessionManager")[0]
346 sm = Glacier2.SessionManagerPrx.checkedCast(sm)
347 try:
348 sm.create("####### STATUS CHECK ########", None)
349 except omero.WrappedCreateSessionException, wcse:
350
351 self.ctx.dbg("Server reachable")
352 self.ctx.rv = 0
353 finally:
354 ic.destroy()
355 except Exc, exc:
356 self.ctx.rv = 1
357 self.ctx.dbg("Server not reachable: "+str(exc))
358 return self.ctx.rv
359
363
367
369 args = Arguments(args)
370 self.ctx.out("Waiting on startup. Use CTRL-C to exit")
371 count = 30
372 while True:
373 count = count - 1
374 if count == 0:
375 self.ctx.die(43, "Failed to startup after 5 minutes")
376 elif 0 == self.status(args):
377 break
378 else:
379 self.ctx.out(".", newline = False)
380 time.sleep(10)
381
383 args = Arguments(args)
384 self.ctx.out("Waiting on shutdown. Use CTRL-C to exit")
385 count = 30
386 while True:
387 count = count - 1
388 if count == 0:
389 self.ctx.die(44, "Failed to shutdown after 5 minutes")
390 elif 0 != self.status(args):
391 break
392 else:
393 self.ctx.out(".", newline = False)
394 time.sleep(10)
395 self.ctx.rv = 0
396
398
399
400 if self._isWindows():
401 svc_name = "OMERO.%s" % self._node()
402 output = self._query_service(svc_name)
403 if 0 <= output.find("DOESNOTEXIST"):
404 self.ctx.die(203, "%s does not exist. Use 'start' first." % svc_name)
405 self.ctx.out(self.ctx.popen(["sc","stop",svc_name]).communicate()[0])
406 self.ctx.out(self.ctx.popen(["sc","delete",svc_name]).communicate()[0])
407 else:
408 command = self._cmd("-e","node shutdown master")
409 try:
410 self.ctx.call(command)
411 except NonZeroReturnCode, nzrc:
412 self.ctx.rv = nzrc.rv
413 self.ctx.out("Was the server already stopped?")
414
415 - def stop(self, args):
418
422
423 - def ice(self, args):
424 args = Arguments(args)
425 command = self._cmd()
426 if len(args) > 0:
427 command.extend(["-e",args.join(" ")])
428 return self.ctx.call(command)
429 else:
430 rv = self.ctx.call(command)
431
433 args = Arguments(args)
434 self.ctx.out("""
435 %s
436 OMERO Diagnostics %s
437 %s
438 """ % ("="*80, VERSION, "="*80))
439
440 def sz_str(sz):
441 for x in ["KB", "MB", "GB"]:
442 sz /= 1000
443 if sz < 1000:
444 break
445 sz = "%.1f %s" % (sz, x)
446 return sz
447
448 def item(cat, msg):
449 cat = cat + ":"
450 cat = "%-12s" % cat
451 self.ctx.out(cat, False)
452 msg = "%-30s " % msg
453 self.ctx.out(msg, False)
454
455 def exists(p):
456 if p.isdir():
457 if not p.exists():
458 self.ctx.out("doesn't exist")
459 else:
460 self.ctx.out("exists")
461 else:
462 if not p.exists():
463 self.ctx.out("n/a")
464 else:
465 warn = 0
466 err = 0
467 for l in p.lines():
468 if l.find("ERROR") >= 0:
469 err += 1
470 elif l.find("WARN") >= 0:
471 warn += 1
472 msg = ""
473 if warn or err:
474 msg = " errors=%-4s warnings=%-4s" % (err, warn)
475 self.ctx.out("%-12s %s" % (sz_str(p.size), msg))
476
477 def version(cmd):
478 item("Commands","%s" % " ".join(cmd))
479 try:
480 p = self.ctx.popen(cmd)
481 except OSError:
482 self.ctx.err("not found")
483 return
484 rv = p.wait()
485 io = p.communicate()
486 try:
487 v = io[0].split()
488 v.extend(io[1].split())
489 v = "".join(v)
490 m = re.match("^\D*(\d[.\d]+\d)\D?.*$", v)
491 v = "%-10s" % m.group(1)
492 self.ctx.out(v, False)
493 try:
494 where = whichall(cmd[0])
495 sz = len(where)
496 if sz == 0:
497 where = unknown
498 else:
499 where = where[0]
500 if sz > 1:
501 where += " -- %s others" % sz
502
503 except:
504 where = "unknown"
505 self.ctx.out("(%s)" % where)
506 except exceptions.Exception, e:
507 self.ctx.err("error:%s" % e)
508
509 version(["java", "-version"])
510 version(["python", "-V"])
511 version(["icegridnode", "--version"])
512 version(["icegridadmin", "--version"])
513 version(["psql", "--version"])
514
515
516 self.ctx.out("")
517 item("Server", "icegridnode")
518 p = self.ctx.popen(self._cmd() + ["-e", "server list"])
519 rv = p.wait()
520 io = p.communicate()
521 if rv != 0:
522 self.ctx.out("not started")
523 self.ctx.dbg("""
524 Stdout:\n%s
525 Stderr:\n%s
526 """ % io)
527 else:
528 self.ctx.out("running")
529 servers = io[0].split()
530 servers.sort()
531 for s in servers:
532 item("Server", "%s" % s)
533 p2 = self.ctx.popen(self._cmd() + ["-e", "server state %s" % s])
534 rv2 = p2.wait()
535 io2 = p2.communicate()
536 if io2[1]:
537 self.ctx.err(io2[1].strip())
538 elif io2[0]:
539 self.ctx.out(io2[0].strip())
540 else:
541 self.ctx.err("UNKNOWN!")
542
543 def log_dir(log, cat, cat2, knownfiles):
544 self.ctx.out("")
545 item(cat, "%s" % log.abspath())
546 exists(log)
547 self.ctx.out("")
548
549 if log.exists():
550 files = log.files()
551 files = set([x.basename() for x in files])
552
553 for x in knownfiles:
554 files.add(x)
555 files = list(files)
556 files.sort()
557 for x in files:
558 item(cat2, x)
559 exists(log / x)
560 item(cat2, "Total size")
561 sz = 0
562 for x in log.walkfiles():
563 sz += x.size
564 self.ctx.out("%-.2f MB" % (float(sz)/1000000.0))
565
566 log_dir(self.ctx.dir / "var" / "log", "Log dir", "Log files",\
567 ["Blitz-0.log", "Tables-0.log", "Processor-0.log", "Indexer-0.log", "FSServer.log", "DropBox.log", "TestDropBox.log", "OMEROweb.log"])
568
569 try:
570 register("admin", AdminControl)
571 except NameError:
572 AdminControl()._main()
573