1
2 """
3 Plugin for viewing and controlling active sessions for a local user.
4
5 Plugin read by omero.cli.Cli during initialization. The method(s)
6 defined here will be added to the Cli class for later use.
7
8 Copyright 2008 Glencoe Software, Inc. All rights reserved.
9 Use is subject to license terms supplied in LICENSE.txt
10
11 """
12
13
14 import os
15 import sys
16 import Ice, Glacier2
17 import time
18 import traceback
19 import exceptions
20 import subprocess
21 import getpass
22 import omero.java
23
24 from omero.util.sessions import SessionsStore
25 from omero.cli import BaseControl, CLI
26 from path import path
27
28 HELP = """Control and create user sessions
29
30 Sessions are stored locally on disk. Several can
31 be active simultaneously, but only one will be used
32 for a single invocation of bin/omero.
33
34 """
35
36 LONGHELP = """
37 Uses the login parameters from %(prog)s to login.
38
39 To list these options, use "%(prog)s -h"
40
41 Sample session:
42 $ bin/omero -s localhost sessions login
43 Username:
44 Password:
45 $ bin/omero -s localhost -u john sessions login
46 Password
47 $ bin/omero -s localhost -k 8afe443f-19fc-4cc4-bf4a-850ec94f4650 sessions login
48 $ bin/omero sessions login
49 Server:
50 Username:
51 Password:
52 $ bin/omero sessions login user@omero.example.com
53 Password:
54 $ bin/omero sessions logout
55 $ bin/omero sessions login
56 Reuse current session? [Y/n]
57 $ bin/omero sessions list
58 $ bin/omero sessions logout
59 $ bin/omero sessions login omero.example.com
60 Username:
61 Password:
62 $ bin/omero sessions logout
63 $ bin/omero -p 24064 sessions login
64 Server:
65 Username:
66 Password:
67 $ bin/omero sessions login my.email@example.com@omero.example.com
68 Password:
69 $ bin/omero -k 8afe443f-19fc-4cc4-bf4a-850ec94f4650 sessions login
70 $ bin/omero sessions clear
71 $ bin/omero sessions list --session-dir=/tmp
72 """
73
75
76 FACTORY = SessionsStore
77
79 try:
80 dirpath = getattr(args, "session_dir", None)
81 return self.FACTORY(dirpath)
82 except OSError, ose:
83 filename = getattr(ose, "filename", dirpath)
84 self.ctx.die(155, "Could not access session dir: %s" % filename)
85
104
109
112
113 - def help(self, args):
115
117 """
118 Goals:
119 If server and key, then don't ask any questions.
120 If nothing requested, and something's active, use it. (i.e. don't require port number)
121 Reconnect if possible (assuming parameters are the same)
122 """
123
124 if self.ctx.conn():
125 self.ctx.err("Active client found")
126 return
127
128 create = getattr(args, "create", None)
129 store = self.store(args)
130 previous = store.get_current()
131
132
133 props = {}
134 if args.port:
135 props["omero.port"] = args.port
136 if args.group:
137 props["omero.group"] = args.group
138
139
140
141
142
143
144 server = getattr(args, "connection", None)
145 name = None
146
147 if args.server:
148 if server:
149 self.ctx.die(3, "Server specified twice: %s and %s" % (server, args.server))
150 else:
151 server = args.server
152
153 if server: server, name = self._parse_conn(server)
154
155 if args.user:
156 if name:
157 self.ctx.die(4, "Username specified twice: %s and %s" % (name, args.user))
158 else:
159 name = args.user
160
161
162
163
164
165
166 pasw = args.password
167 if args.key:
168 if name:
169 self.ctx.err("Overriding name since session set")
170 name = args.key
171 if args.password:
172 self.ctx.err("Ignoring password since key set")
173 pasw = args.key
174
175
176
177
178
179
180 elif previous[0] and previous[1]:
181
182 server_differs = (server is not None and server != previous[0])
183 name_differs = (name is not None and name != previous[1])
184
185 if not create and not server_differs and not name_differs:
186 try:
187 conflicts = store.conflicts(previous[0], previous[1], previous[2], props, True)
188 if conflicts:
189 self.ctx.dbg("Not attaching because of conflicts: %s" % conflicts)
190 else:
191 rv = store.attach(*previous)
192 return self.handle(rv, "Using")
193 except exceptions.Exception, e:
194 self.ctx.dbg("Exception on attach: %s" % traceback.format_exc(e))
195 self.ctx.dbg("Exception on attach: %s" % e)
196
197 self.ctx.out("Previously logged in to %s as %s" % (previous[0], previous[1]))
198
199
200
201
202
203
204 if not server: server, name = self._get_server(store)
205 if not name: name = self._get_username()
206
207 props["omero.host"] = server
208 props["omero.user"] = name
209
210 rv = None
211 if not create:
212 available = store.available(server, name)
213 for uuid in available:
214 conflicts = store.conflicts(server, name, uuid, props)
215 if conflicts:
216 self.ctx.dbg("Skipping %s due to conflicts: %s" % (uuid, conflicts))
217 continue
218 try:
219 rv = store.attach(server, name, uuid)
220 store.set_current(server, name, uuid)
221 action = "Reconnected to"
222 break
223 except:
224 self.ctx.dbg("Removing %s" % uuid)
225 store.clear(server, name, uuid)
226 continue
227
228 if not rv:
229 tries = 3
230 while True:
231 try:
232 if not pasw:
233 pasw = self.ctx.input("Password:", hidden = True, required = True)
234 rv = store.create(name, pasw, props)
235 break
236 except Glacier2.PermissionDeniedException, pde:
237 tries -= 1
238 if not tries:
239 self.ctx.die(524, "3 incorrect password attempts")
240 else:
241 self.ctx.err(pde.reason)
242 pasw = None
243 except Ice.ConnectionRefusedException:
244 self.ctx.die(554, "Ice.ConnectionRefusedException: %s isn't running" % server)
245 except Ice.DNSException:
246 self.ctx.die(555, "Ice.DNSException: bad host name: '%s'" % server)
247 except exceptions.Exception, e:
248 exc = traceback.format_exc()
249 self.ctx.dbg(exc)
250 self.ctx.die(556, "InternalException: Failed to connect: %s" % e)
251 action = "Created"
252
253 return self.handle(rv, action)
254
255 - def handle(self, rv, action):
256 """
257 Handles a new connection
258 """
259 client, uuid, idle, live = rv
260 sf = client.sf
261
262
263 client.enableKeepAlive(300)
264 ec = sf.getAdminService().getEventContext()
265 self.ctx._event_context = ec
266 self.ctx._client = client
267
268 msg = "%s session %s (%s@%s)." % (action, uuid, ec.userName, client.getProperty("omero.host"))
269 if idle:
270 msg = msg + " Idle timeout: %s min." % (float(idle)/60/1000)
271 if live:
272 msg = msg + " Expires in %s min." % (float(live)/60/1000)
273
274 msg += (" Current group: %s" % sf.getAdminService().getEventContext().groupName)
275
276 self.ctx.err(msg)
277
289
291 store = self.store(args)
292 client = self.ctx.conn(args)
293 sf = client.sf
294 admin = sf.getAdminService()
295
296 try:
297 group_id = long(args.target)
298 group_name = admin.getGroup(group_id).name.val
299 except ValueError, ve:
300 group_name = args.target
301 group_id = admin.lookupGroup(group_name).id.val
302
303 ec = admin.getEventContext()
304 old_id = ec.groupId
305 old_name = ec.groupName
306 if old_id == group_id:
307 self.ctx.err("Group '%s' (id=%s) is already active" % (group_name, group_id))
308 else:
309 sf.setSecurityContext(omero.model.ExperimenterGroupI(group_id, False))
310 self.ctx.out("Group '%s' (id=%s) switched to '%s' (id=%s)" % (old_name, old_id, group_name, group_id))
311
312 - def list(self, args):
313 import Glacier2
314 store = self.store(args)
315 s = store.contents()
316 previous = store.get_current()
317
318
319
320
321 headers = ("Server", "User", "Group", "Session", "Active", "Started")
322 results = dict([(x,[]) for x in headers])
323 for server, names in s.items():
324 for name, sessions in names.items():
325 for uuid, props in sessions.items():
326 rv = None
327 msg = "True"
328 grp = "Unknown"
329 started = "Unknown"
330 try:
331 rv = store.attach(server, name, uuid)
332 grp = rv[0].sf.getAdminService().getEventContext().groupName
333 started = rv[0].sf.getSessionService().getSession(uuid).started.val
334 started = time.ctime(started / 1000.0)
335 rv[0].closeSession()
336 except Glacier2.PermissionDeniedException, pde:
337 msg = pde.reason
338 except exceptions.Exception, e:
339 self.ctx.dbg("Exception on attach: %s" % e)
340 msg = "Unknown exception"
341 if rv is None and args.purge:
342 self.ctx.dbg("Purging %s / %s / %s" % (server, name, uuid))
343 store.remove(server, name, uuid)
344
345 if server == previous[0] and name == previous[1] and uuid == previous[2]:
346 msg = "Logged in"
347
348 results["Server"].append(server)
349 results["User"].append(name)
350 results["Group"].append(grp)
351 results["Session"].append(uuid)
352 results["Active"].append(msg)
353 results["Started"].append(started)
354
355 from omero.util.text import Table, Column
356 columns = tuple([Column(x, results[x]) for x in headers])
357 self.ctx.out(str(Table(*columns)))
358
364
377 t = T()
378 t.client = self.ctx.conn(args)
379 t.event = get_event(name="keepalive")
380 t.start()
381 try:
382 self.ctx.out("Running keep alive every %s seconds" % args.frequency)
383 self.ctx.input("Press enter to cancel.")
384 finally:
385 t.client = None
386 t.event.set()
387
388 - def file(self, args):
393
394 - def conn(self, properties={}, profile=None, args=None):
395 """
396 Either creates or returns the exiting omero.client instance.
397 Uses the comm() method with the same signature.
398 """
399
400 if self._client:
401 return self._client
402
403 import omero
404 try:
405 data = self.initData(properties)
406 self._client = omero.client(sys.argv, id = data)
407 self._client.setAgent("OMERO.cli")
408 self._client.createSession()
409 return self._client
410 except Exc, exc:
411 self._client = None
412 raise
413
414
415
416
417
419 try:
420 idx = server.rindex("@")
421 return server[idx+1:], server[0:idx]
422 except ValueError:
423 return server, None
424
426 defserver = store.last_host()
427 rv = self.ctx.input("Server: [%s]" % defserver)
428 if not rv:
429 return defserver, None
430 else:
431 return self._parse_conn(rv)
432
434 defuser = getpass.getuser()
435 rv = self.ctx.input("Username: [%s]" % defuser)
436 if not rv:
437 return defuser
438 else:
439 return rv
440
441
442 try:
443 register("sessions", SessionsControl, HELP)
444 except NameError:
445 if __name__ == "__main__":
446 cli = CLI()
447 cli.register("sessions", SessionsControl, HELP)
448 cli.invoke(sys.argv[1:])
449