Package omero :: Package plugins :: Module admin
[hide private]
[frames] | no frames]

Source Code for Module omero.plugins.admin

  1  #!/usr/bin/env python 
  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   
38 -class AdminControl(BaseControl):
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 # Windows utility methods 99 # 100 if has_win32:
101 - def _query_service(unused, svc_name):
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
120 - def events(self, svc_name):
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
132 - def events(self, svc_name):
133 self.ctx.die(666, "Could not import win32service and/or win32evtlogutil")
134
135 - def _query_service(self, svc_name):
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) # popen 143 output = popen.communicate()[0] 144 if 0 <= output.find("1060"): 145 return "DOESNOTEXIST" 146 else: 147 return output
148 149 # 150 # End Windows Methods 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 # Relative to cwd 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
190 - def _descript(self, first, other):
191 if first != None and len(first) > 0: 192 # Relative to cwd 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
209 - def checkwindows(self, *args):
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 # Commands 249 # 250
251 - def startasync(self, args):
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 ##if 0 != self.status(args): 261 ## self.ctx.err("Server already running") 262 263 self._initDir() 264 props = self._properties() 265 # Do a check to see if we've started before. 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 # Now check if the server exists 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 # By default: "NT Authority\LocalService" 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]) # popen 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]) # popen 304 305 # Then check if the server is already running 306 if 0 <= output.find("RUNNING"): 307 self.ctx.die(201, "%s is already running. Use stop first" % svc_name) 308 309 # Finally start the service 310 output = self.ctx.popen(["sc","start",svc_name]).communicate()[0] # popen 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
316 - def start(self, args):
317 self.startasync(args) 318 self.waitup(args)
319
320 - def deploy(self, args):
321 args = Arguments(args) 322 first, other = args.firstOther() 323 descript = self._descript(first, other) 324 325 # TODO : Doesn't properly handle whitespace 326 command = ["icegridadmin",self._intcfg(),"-e"," ".join(["application","update", str(descript)] + other)] 327 self.ctx.call(command)
328
329 - def status(self, args):
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() # popen 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) # Not adding "omero.client.uuid" 349 except omero.WrappedCreateSessionException, wcse: 350 # Only the server will throw one of these 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
360 - def __DISABLED__restart(self, args):
361 self.stop(args) 362 self.start(args)
363
364 - def __DISABLED__restartasync(self, args):
365 self.stop(args) 366 self.startasync(args)
367
368 - def waitup(self, args):
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
382 - def waitdown(self, args):
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
397 - def stopasync(self, args):
398 ##if 0 == self.status(args): 399 ## self.ctx.err("Server not running") 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]) # popen 406 self.ctx.out(self.ctx.popen(["sc","delete",svc_name]).communicate()[0]) # popen 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):
416 self.stopasync(args) 417 self.waitdown(args)
418
419 - def check(self, args):
420 # print "Check db. Have a way to load the db control" 421 pass
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
432 - def diagnostics(self, args):
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"]) # popen 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]) # popen 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 # Adding known names just in case 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