IMP  2.0.0
The Integrative Modeling Platform
PyroUtils.py
1 ##
2 ## The Inferential Structure Determination (ISD) software library
3 ##
4 ## Authors: Darima Lamazhapova and Wolfgang Rieping
5 ##
6 ## Copyright (C) Michael Habeck and Wolfgang Rieping
7 ##
8 ## All rights reserved.
9 ##
10 ## NO WARRANTY. This library is provided 'as is' without warranty of any
11 ## kind, expressed or implied, including, but not limited to the implied
12 ## warranties of merchantability and fitness for a particular purpose or
13 ## a warranty of non-infringement.
14 ##
15 ## Distribution of substantively modified versions of this module is
16 ## prohibited without the explicit permission of the copyright holders.
17 ##
18 
19 import os
20 import sys
21 from socket import gethostname
22 from string import split, join
23 from threading import Lock, Thread
24 from time import time, sleep
25 
26 import Pyro.naming
27 import Pyro.core
28 from Pyro.errors import PyroError, NamingError, ConnectionDeniedError
29 from Pyro.naming import NameServerProxy
30 
31 default_debug = False
32 
33 default_group = ':%s' % os.environ['USER']
34 Pyro.config.PYRO_NS_DEFAULTGROUP = default_group
35 
36 if 'PYROGRID_TIMEOUT' in os.environ:
37  default_timeout = eval(os.environ['PYROGRID_TIMEOUT'])
38 else:
39  default_timeout = 600.0
40 
41 if 'PYROGRID_WAIT' in os.environ:
42  default_wait = eval(os.environ['PYROGRID_WAIT'])
43 else:
44  default_wait = 5.0
45 
46 def absolute_uri(uri, ns = None):
47 
48  if not isinstance(ns, NameServerProxy):
49  if ns is None or ns == '':
50  ns = Pyro.naming.NameServerLocator().getNS()
51  else:
52  ns = Pyro.naming.NameServerLocator().getNS(host=ns)
53 
54  return ns.fullName(uri)
55 
56 def group_uri_list(group_uri, ns = None):
57  """
58  Returns the list of all URIs given the group_uri
59 
60  """
61  if not isinstance(ns, NameServerProxy):
62  if ns is None or ns == '':
63  ns = Pyro.naming.NameServerLocator().getNS()
64  else:
65  ns = Pyro.naming.NameServerLocator().getNS(host=ns)
66 
67  level_0 = group_uri
68 
69  try:
70  lst = ns.list(level_0) ## level_0 is a group
71 
72  level_1 = [ join( (level_0, lst[i][0]), '.' ) for i in range(0, len(lst)) ]
73  level_1_expanded = []
74 
75  for level_1_i in level_1:
76  level_1_expanded += group_uri_list(level_1_i, ns)
77 
78  except NamingError:
79 
80  try:
81  ns.resolve(level_0)
82  level_1_expanded = [ns.fullName(level_0)] ## level_0 is not a group, it is full URI
83 
84  except NamingError:
85  level_1_expanded = [] ## level_0 is not registered with ns
86 
87  return level_1_expanded
88 
89 def _new_id(xlst):
90  """
91  returns a number which is not in xlst
92 
93  """
94 
95 
96  if len(xlst) == 0: x = 0 ## 'obj_name.0'
97  else: ## 'obj_name.x'
98  x = len(xlst)
99  xlst.sort()
100  for i in range(len(xlst)):
101  if xlst[i] != i:
102  x = i
103  break
104  return x
105 
106 def create_unique_uri(obj_name, n = 1, ns = None):
107  """
108  obj_name = e.g. URI will be 'obj_name.6'
109  uri_list = group_uri_list(obj_name)
110 
111  Create unique name 'obj_name.x' (the name which is not in uri_list)
112 
113  """
114  if default_debug:
115  print 'PyroUtils.create_unique_uri: %s URIs for %s...' % (n, obj_name)
116 
117  if not isinstance(ns, NameServerProxy):
118  if ns is None or ns == '':
119  ns = Pyro.naming.NameServerLocator().getNS()
120  else:
121  ns = Pyro.naming.NameServerLocator().getNS(host=ns)
122 
123  old_uri_list = group_uri_list(obj_name, ns)
124 
125  xlst = [] ## list of 'x' components of 'smth.obj_name.x' of URI in uri_list
126  for uri in old_uri_list: xlst.append( eval(uri.split('.')[-1]) )
127 
128  new_uri_list = []
129 
130  for i in range(n):
131 
132  x = _new_id(xlst)
133  new_uri_list.append( ns.fullName(join( (obj_name, str(x)), '.' )) )
134  xlst.append(x)
135 
136  return new_uri_list
137 
138 def create_groups(obj_uri, ns = None):
139  """
140  Creates groups for the obj_uri
141 
142  Example: for 'factory.horse--bio.1'
143  creates groups factory and factory.horse--bio
144 
145  """
146 
147  if not isinstance(ns, NameServerProxy):
148  if ns is None or ns == '':
149  ns = Pyro.naming.NameServerLocator().getNS()
150  else:
151  ns = Pyro.naming.NameServerLocator().getNS(host=ns)
152 
153  try: ns.createGroup(default_group)
154  except NamingError: pass
155 
156  groups = obj_uri.split('.')[:-1]
157 
158  for i in range(1, len(groups)):
159  groups[i] = join( groups[i-1:i+1], '.')
160 
161  for i in range(0, len(groups)):
162  try:
163  ns.createGroup(groups[i])
164  except NamingError:
165  pass
166 
167 def is_stopped(obj_uri, timeout = default_timeout, ns = None):
168  """
169  Checks if the Pyro remote object with URI obj_uri
170  has been stopped (gracefully).
171 
172  """
173  if default_debug:
174  print 'PyroUtils.is_stopped: for %s...' % obj_uri
175 
176  if not isinstance(ns, NameServerProxy):
177  if ns is None or ns == '':
178  ns = Pyro.naming.NameServerLocator().getNS()
179  else:
180  ns = Pyro.naming.NameServerLocator().getNS(host = ns)
181 
182 
183  stopped = False
184  t0 = time()
185 
186  while (not stopped) and time()-t0 < timeout:
187  try:
188  ns.resolve(obj_uri)
189  except Pyro.errors.NamingError:
190  stopped = True
191  pass
192 
193  if stopped:
194  return True
195  else:
196  print 'PyroUtils.is_stopped: Object with URI %s could not ' +\
197  'be shut down during timeout' % obj_uri
198  return False
199 
200 def launch_instance(obj_instance, obj_uri, delegate, \
201  nshost = None, debug = True, shutdown = False):
202  """
203  Launches obj_instance as Pyro daemon on the current host.
204 
205  obj_instance = the class of the Pyro implementation object
206  obj_uri = URI for the object to register in the Name Server
207  <- create_uri(obj_name, nshost)
208  delegate = whether to use the delegate approach or the regular
209  objBase subclassing approach
210 
211  Function also assigns:
212 
213  obj_instance._pyro_stop = False
214  obj_instance._pyro_suppl['uri'] = obj_uri
215  ...
216 
217  """
218 
219  if debug:
220  print 'PyroUtils.launch_instance: %s, URI %s, PID %s on %s' \
221  % (obj_instance, obj_uri, os.getpid(), gethostname())
222 
223  ## initialize the server and set the default namespace group
224 
225  Pyro.config.PYRO_MOBILE_CODE = 1 #TODO: this should spare us
226  #the copying of all files at the initialization
227  #of PyroGrid()
228  Pyro.core.initServer()
229 
230  ## locate the NS
231 
232  if nshost is None or nshost == '':
233  ns = Pyro.naming.NameServerLocator().getNS()
234  else:
235  ns = Pyro.naming.NameServerLocator().getNS(host=nshost)
236 
237  try:
238  ns.resolve(obj_uri)
239  except NamingError: pass
240  else:
241  print 'Object with URI %s already exists, unregister first!' % obj_uri
242  raise
243 
244  create_groups(obj_uri, ns)
245 
246  ## start daemon
247 
248  if debug:
249  print 'launching pyro daemon and nameserver'
250  daemon = Pyro.core.Daemon()
251  daemon.useNameServer(ns)
252 
253  ## connect a new object implementation (first unregister previous one)
254 
255  obj_instance._pyro_stop = False ## used to stop execution
256  obj_instance._pyro_suppl = {}
257  obj_instance._pyro_suppl['uri'] = obj_uri ## to monitor the status of the
258  obj_instance._pyro_suppl['nshost'] = nshost ## proxy (stopped or running)
259  obj_instance._pyro_suppl['host'] = gethostname() ## (for debugging)
260 
261  obj_instance._pyro_suppl['callable'] = {}
262  for attr in dir(obj_instance):
263  obj_instance._pyro_suppl['callable'][attr] = callable(getattr(obj_instance,attr))
264 
265  if isinstance(obj_instance, type(Thread())):
266  obj_instance.start()
267 
268  #print 'PyroUtils.launch_instance: Connecting to a daemon...'
269 
270  if delegate:
271  #print 'PyroUtils.launch_instance: Delegating...'
272  obj = Pyro.core.ObjBase()
273  obj.delegateTo(obj_instance)
274  daemon.connectPersistent(obj, obj_uri)
275  else:
276  ## obj_instance in this case must be inherited from Pyro.core.ObjBase
277  daemon.connectPersistent(obj_instance, obj_uri)
278 
279  print 'PyroUtils.launch_instance: Remote object "%s" is ready' % obj_uri
280 
281  try:
282  #listen for requests as long as condition returns True
283  #by default, each loop lasts 3 seconds
284  daemon.requestLoop(condition = lambda:
285  not obj_instance._pyro_stop)
286  except KeyboardInterrupt:
287  pass
288 
289  print 'PyroUtils.launch_instance: Shutting down %s gracefully' % obj_uri
290 
291  #should not need this since the daemon does this anyway
292  if delegate:
293  daemon.disconnect(obj)
294  else:
295  daemon.disconnect(obj_instance)
296 
297  if shutdown:
298  ## This will cleanly stop all threads that might
299  ## still be running.
300  daemon.shutdown()
301  print 'Exiting'
302  else:
303  print 'Finished, keeping interperter alive and Pyro daemon running'
304 
305 def get_proxy(obj_uri, ns = None, attrproxy = True, timeout = default_timeout):
306 
307  if default_debug:
308  print 'PyroUtils.get_proxy: "%s" using nameserver "%s"...' \
309  % (obj_uri, ns)
310 
311  Pyro.config.PYRO_MOBILE_CODE = 1
312 
313  Pyro.core.initClient()
314 
315  if not isinstance(ns, NameServerProxy):
316  if ns is None or ns == '':
317  ns = Pyro.naming.NameServerLocator().getNS()
318  else:
319  ns = Pyro.naming.NameServerLocator().getNS(host=ns)
320 
321  t0 = time()
322  resolved = False
323 
324  while not resolved:
325  try:
326  pyro_uri = ns.resolve(obj_uri)
327  resolved = True
328 
329  except Pyro.errors.NamingError, x:
330 
331  if time()-t0 < timeout:
332  sleep(default_wait)
333 
334  else:
335  print 'PyroUtils.get_proxy: could not locate object "%s" using "%s"' \
336  % (obj_uri, ns)
337  raise
338 
339  if default_debug:
340  print 'PyroUtils.get_proxy: returning the proxy "%s"' % pyro_uri
341 
342  if attrproxy:
343  return pyro_uri.getAttrProxy()
344  else:
345  return pyro_uri.getProxy()
346 
347 def get_nameserver(nshost):
348 
349  if nshost is None or nshost == '':
350  return Pyro.naming.NameServerLocator().getNS()
351  else:
352  return Pyro.naming.NameServerLocator().getNS(host = nshost)
353 
354 def unregister(obj_uri, ns = None):
355 
356  if default_debug:
357  print 'PyroUtils.unregister: Unregistering %s...' % obj_uri
358 
359  if not isinstance(ns, NameServerProxy):
360  if ns is None or ns == '':
361  ns = Pyro.naming.NameServerLocator().getNS()
362  else:
363  ns = Pyro.naming.NameServerLocator().getNS(host = ns)
364 
365  ns.unregister(obj_uri)