1
2
3 """
4 Plugin for viewing and controlling active sessions for a local user.
5
6 Plugin read by omero.cli.Cli during initialization. The method(s)
7 defined here will be added to the Cli class for later use.
8
9 Copyright 2008 Glencoe Software, Inc. All rights reserved.
10 Use is subject to license terms supplied in LICENSE.txt
11
12 """
13
14
15 import sys
16 import Ice
17 import IceImport
18 import time
19 import traceback
20 import omero.java
21
22 IceImport.load("Glacier2_Router_ice")
23
24 from Glacier2 import PermissionDeniedException
25
26 from omero.util import get_user
27 from omero.util.sessions import SessionsStore
28 from omero.cli import BaseControl, CLI
29
30 HELP = """Control and create user sessions
31
32 Sessions are stored locally on disk. Several can
33 be active simultaneously, but only one will be used
34 for a single invocation of bin/omero.
35
36 """
37
38 LONGHELP = """
39 Uses the login parameters from %(prog)s to login.
40
41 To list these options, use "%(prog)s -h"
42
43 Sample session:
44 $ bin/omero -s localhost sessions login
45 Username:
46 Password:
47 $ bin/omero -s localhost -u john sessions login
48 Password
49 $ bin/omero -s localhost -k 8afe443f-19fc-4cc4-bf4a-850ec94f4650 \
50 sessions login
51 $ bin/omero sessions login
52 Server:
53 Username:
54 Password:
55 $ bin/omero sessions login user@omero.example.com
56 Password:
57 $ bin/omero sessions login user@omero.example.com:24064
58 Password:
59 $ bin/omero sessions logout
60 $ bin/omero sessions login
61 Reuse current session? [Y/n]
62 $ bin/omero sessions list
63 $ bin/omero sessions logout
64 $ bin/omero sessions login omero.example.com
65 Username:
66 Password:
67 $ bin/omero sessions logout
68 $ bin/omero -p 24064 sessions login
69 Server:
70 Username:
71 Password:
72 $ bin/omero sessions login my.email@example.com@omero.example.com
73 Password:
74 $ bin/omero -k 8afe443f-19fc-4cc4-bf4a-850ec94f4650 sessions login
75 $ bin/omero sessions clear
76 $ bin/omero sessions list --session-dir=/tmp
77 """
78
79
81
82 FACTORY = SessionsStore
83
85 try:
86 dirpath = getattr(args, "session_dir", None)
87 return self.FACTORY(dirpath)
88 except OSError, ose:
89 filename = getattr(ose, "filename", dirpath)
90 self.ctx.die(155, "Could not access session dir: %s" % filename)
91
136
147
151
152 - def help(self, args):
154
156 """
157 Goals:
158 If server and key, then don't ask any questions.
159 If nothing requested, and something's active, use it. (i.e. don't
160 require port number)
161 Reconnect if possible (assuming parameters are the same)
162 """
163
164 if self.ctx.conn():
165 self.ctx.err("Active client found")
166 return
167
168 create = getattr(args, "create", None)
169 store = self.store(args)
170 previous = store.get_current()
171 try:
172 previous_props = store.get(*previous)
173 previous_port = previous_props.get(
174 "omero.port", str(omero.constants.GLACIER2PORT))
175 except:
176 previous_port = str(omero.constants.GLACIER2PORT)
177
178
179 props = {}
180 if args.group:
181 props["omero.group"] = args.group
182
183
184
185
186
187
188
189 server = getattr(args, "connection", None)
190 name = None
191 port = None
192
193 if args.server:
194 if server:
195 self.ctx.die(3, "Server specified twice: %s and %s"
196 % (server, args.server))
197 else:
198 server = args.server
199
200 if server:
201 server, name, port = self._parse_conn(server, name)
202
203 if args.user:
204 if name:
205 self.ctx.die(4, "Username specified twice: %s and %s"
206 % (name, args.user))
207 else:
208 name = args.user
209
210 if args.port:
211 if port:
212 self.ctx.die(5, "Port specified twice: %s and %s"
213 % (port, args.port))
214 else:
215 port = args.port
216
217
218
219
220
221
222 pasw = args.password
223 if args.key:
224 if name:
225 self.ctx.err("Overriding name since session set")
226 name = args.key
227 if args.password:
228 self.ctx.err("Ignoring password since key set")
229 pasw = args.key
230
231
232
233
234
235
236 elif previous[0] and previous[1]:
237
238 server_differs = (server is not None and server != previous[0])
239 name_differs = (name is not None and name != previous[1])
240 port_differs = (port is not None and port != previous_port)
241
242 if not create and not server_differs and not name_differs \
243 and not port_differs:
244 try:
245 if previous[2] is not None:
246
247 conflicts = store.conflicts(
248 previous[0], previous[1], previous[2], props,
249 True)
250 if conflicts:
251 self.ctx.dbg("Not attaching because of"
252 " conflicts: %s" % conflicts)
253 else:
254 rv = store.attach(*previous)
255 return self.handle(rv, "Using")
256 self.ctx.out("Previously logged in to %s:%s as %s"
257 % (previous[0], previous_port,
258 previous[1]))
259 except Exception, e:
260 self.ctx.out("Previous session expired for %s on"
261 " %s:%s" % (previous[1], previous[0],
262 previous_port))
263 self.ctx.dbg("Exception on attach: %s"
264 % traceback.format_exc(e))
265 try:
266 store.remove(*previous)
267 except OSError, ose:
268 self.ctx.dbg("Session file missing: %s" % ose)
269 except:
270 self.ctx.dbg("Exception on remove: %s"
271 % traceback.format_exc(e))
272
273
274 self.ctx.err("Failed to remove session: %s" % e)
275
276
277
278
279
280
281 if not server:
282 server, name, prt = self._get_server(store, name)
283 if not name:
284 name = self._get_username(previous[1])
285
286 props["omero.host"] = server
287 props["omero.user"] = name
288 if port:
289 props["omero.port"] = port
290
291 rv = None
292
293
294
295
296
297
298 if args.key:
299 stored_name = store.find_name_by_key(server, args.key)
300 if not stored_name:
301
302
303
304 self.ctx.dbg("No name found for %s." % args.key)
305 rv = self.attach(store, server, args.key, args.key, props,
306 False, set_current=False)
307 else:
308 rv = self.check_and_attach(store, server, stored_name,
309 args.key, props)
310 action = "Joined"
311 if not rv:
312 self.ctx.die(523, "Bad session key")
313 elif not create:
314 available = store.available(server, name)
315 for uuid in available:
316 rv = self.check_and_attach(store, server, name, uuid, props)
317 action = "Reconnected to"
318
319 if not rv:
320 tries = 3
321 while True:
322 try:
323 if not pasw:
324 pasw = self.ctx.input("Password:", hidden=True,
325 required=True)
326 rv = store.create(name, pasw, props)
327 break
328 except PermissionDeniedException, pde:
329 tries -= 1
330 if not tries:
331 self.ctx.die(524, "3 incorrect password attempts")
332 else:
333 self.ctx.err(pde.reason)
334 pasw = None
335 except Ice.ConnectionRefusedException:
336 if port:
337 self.ctx.die(554, "Ice.ConnectionRefusedException:"
338 " %s:%s isn't running" % (server, port))
339 else:
340 self.ctx.die(554, "Ice.ConnectionRefusedException: %s"
341 " isn't running" % server)
342 except Ice.DNSException:
343 self.ctx.die(555, "Ice.DNSException: bad host name: '%s'"
344 % server)
345 except Exception, e:
346 exc = traceback.format_exc()
347 self.ctx.dbg(exc)
348 self.ctx.die(556, "InternalException: Failed to connect:"
349 " %s" % e)
350 action = "Created"
351
352 return self.handle(rv, action)
353
355 """
356 Checks for conflicts in the settings for this session,
357 and if there are none, then attempts an "attach()". If
358 that fails, the session is removed.
359 """
360
361 exists = store.exists(server, name, uuid)
362
363 if exists:
364 conflicts = store.conflicts(server, name, uuid, props)
365 if conflicts:
366 self.ctx.dbg("Skipping %s due to conflicts: %s"
367 % (uuid, conflicts))
368 return None
369
370 return self.attach(store, server, name, uuid, props, exists)
371
372 - def attach(self, store, server, name, uuid, props, exists,
373 set_current=True):
374 rv = None
375 try:
376 if exists:
377 rv = store.attach(server, name, uuid, set_current=set_current)
378 else:
379 rv = store.create(name, name, props, set_current=set_current)
380 except Exception, e:
381 self.ctx.dbg("Removing %s: %s" % (uuid, e))
382 store.clear(server, name, uuid)
383 return rv
384
385 - def handle(self, rv, action):
411
422
423
424
426 client = self.ctx.conn(args)
427 sf = client.sf
428 admin = sf.getAdminService()
429
430 try:
431 group_id = long(args.target)
432 group_name = admin.getGroup(group_id).name.val
433 except ValueError:
434 group_name = args.target
435 group_id = admin.lookupGroup(group_name).id.val
436
437 ec = self.ctx._event_context
438 old_id = ec.groupId
439 old_name = ec.groupName
440 if old_id == group_id:
441 self.ctx.err("Group '%s' (id=%s) is already active"
442 % (group_name, group_id))
443 else:
444 sf.setSecurityContext(omero.model.ExperimenterGroupI(group_id,
445 False))
446 self.ctx.out("Group '%s' (id=%s) switched to '%s' (id=%s)"
447 % (old_name, old_id, group_name, group_id))
448
449 - def list(self, args):
450 store = self.store(args)
451 s = store.contents()
452 previous = store.get_current()
453
454
455
456
457
458 headers = ("Server", "User", "Group", "Session", "Active", "Started")
459 results = dict([(x, []) for x in headers])
460 for server, names in s.items():
461 for name, sessions in names.items():
462 for uuid, props in sessions.items():
463 rv = None
464 msg = "True"
465 grp = "Unknown"
466 started = "Unknown"
467 port = None
468 try:
469 if props:
470 port = props.get("omero.port", port)
471 rv = store.attach(server, name, uuid)
472 try:
473 a_s = rv[0].sf.getAdminService()
474 grp = a_s.getEventContext().groupName
475 s_s = rv[0].sf.getSessionService()
476 started = s_s.getSession(uuid).started.val
477 started = time.ctime(started / 1000.0)
478 finally:
479 if rv:
480 rv[0].closeSession()
481 except PermissionDeniedException, pde:
482 msg = pde.reason
483 except Exception, e:
484 self.ctx.dbg("Exception on attach: %s" % e)
485 msg = "Unknown exception"
486
487 if rv is None and args.purge:
488 self.ctx.dbg("Purging %s / %s / %s"
489 % (server, name, uuid))
490 store.remove(server, name, uuid)
491
492 if server == previous[0] and name == previous[1] and \
493 uuid == previous[2]:
494 msg = "Logged in"
495
496 if port:
497 results["Server"].append("%s:%s" % (server, port))
498 else:
499 results["Server"].append(server)
500
501 results["User"].append(name)
502 results["Group"].append(grp)
503 results["Session"].append(uuid)
504 results["Active"].append(msg)
505 results["Started"].append(started)
506
507 from omero.util.text import Table, Column
508 columns = tuple([Column(x, results[x]) for x in headers])
509 self.ctx.out(str(Table(*columns)))
510
516
530 t = T()
531 t.client = self.ctx.conn(args)
532 t.event = get_event(name="keepalive")
533 t.start()
534 try:
535 self.ctx.out("Running keep alive every %s seconds"
536 % args.frequency)
537 self.ctx.input("Press enter to cancel.")
538 finally:
539 t.client = None
540 t.event.set()
541
542 - def file(self, args):
547
548 - def conn(self, properties=None, profile=None, args=None):
549 """
550 Either creates or returns the exiting omero.client instance.
551 Uses the comm() method with the same signature.
552 """
553
554 if properties is None:
555 properties = {}
556
557 if self._client:
558 return self._client
559
560 import omero
561 try:
562 data = self.initData(properties)
563 self._client = omero.client(sys.argv, id=data)
564 self._client.setAgent("OMERO.cli")
565 self._client.createSession()
566 return self._client
567 except Exception:
568 self._client = None
569 raise
570
571
572
573
574
591
599
601 if defuser is None:
602 defuser = get_user("root")
603 rv = self.ctx.input("Username: [%s]" % defuser)
604 if not rv:
605 return defuser
606 else:
607 return rv
608
609
610 try:
611 register("sessions", SessionsControl, HELP)
612 except NameError:
613 if __name__ == "__main__":
614 cli = CLI()
615 cli.register("sessions", SessionsControl, HELP)
616 cli.invoke(sys.argv[1:])
617