pyro_ext.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  2. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  3. #
  4. # This file is part of logilab-common.
  5. #
  6. # logilab-common is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU Lesser General Public License as published by the Free
  8. # Software Foundation, either version 2.1 of the License, or (at your option) any
  9. # later version.
  10. #
  11. # logilab-common is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU Lesser General Public License along
  17. # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
  18. """Python Remote Object utilities
  19. Main functions available:
  20. * `register_object` to expose arbitrary object through pyro using delegation
  21. approach and register it in the nameserver.
  22. * `ns_unregister` unregister an object identifier from the nameserver.
  23. * `ns_get_proxy` get a pyro proxy from a nameserver object identifier.
  24. """
  25. __docformat__ = "restructuredtext en"
  26. import logging
  27. import tempfile
  28. from Pyro import core, naming, errors, util, config
  29. _LOGGER = logging.getLogger('pyro')
  30. _MARKER = object()
  31. config.PYRO_STORAGE = tempfile.gettempdir()
  32. def ns_group_and_id(idstr, defaultnsgroup=_MARKER):
  33. try:
  34. nsgroup, nsid = idstr.rsplit('.', 1)
  35. except ValueError:
  36. if defaultnsgroup is _MARKER:
  37. nsgroup = config.PYRO_NS_DEFAULTGROUP
  38. else:
  39. nsgroup = defaultnsgroup
  40. nsid = idstr
  41. if nsgroup is not None and not nsgroup.startswith(':'):
  42. nsgroup = ':' + nsgroup
  43. return nsgroup, nsid
  44. def host_and_port(hoststr):
  45. if not hoststr:
  46. return None, None
  47. try:
  48. hoststr, port = hoststr.split(':')
  49. except ValueError:
  50. port = None
  51. else:
  52. port = int(port)
  53. return hoststr, port
  54. _DAEMONS = {}
  55. _PYRO_OBJS = {}
  56. def _get_daemon(daemonhost, start=True):
  57. if not daemonhost in _DAEMONS:
  58. if not start:
  59. raise Exception('no daemon for %s' % daemonhost)
  60. if not _DAEMONS:
  61. core.initServer(banner=0)
  62. host, port = host_and_port(daemonhost)
  63. daemon = core.Daemon(host=host, port=port)
  64. _DAEMONS[daemonhost] = daemon
  65. return _DAEMONS[daemonhost]
  66. def locate_ns(nshost):
  67. """locate and return the pyro name server to the daemon"""
  68. core.initClient(banner=False)
  69. return naming.NameServerLocator().getNS(*host_and_port(nshost))
  70. def register_object(object, nsid, defaultnsgroup=_MARKER,
  71. daemonhost=None, nshost=None, use_pyrons=True):
  72. """expose the object as a pyro object and register it in the name-server
  73. if use_pyrons is False, then the object is exposed, but no
  74. attempt to register it to a pyro nameserver is made.
  75. return the pyro daemon object
  76. """
  77. nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
  78. daemon = _get_daemon(daemonhost)
  79. if use_pyrons:
  80. nsd = locate_ns(nshost)
  81. # make sure our namespace group exists
  82. try:
  83. nsd.createGroup(nsgroup)
  84. except errors.NamingError:
  85. pass
  86. daemon.useNameServer(nsd)
  87. # use Delegation approach
  88. impl = core.ObjBase()
  89. impl.delegateTo(object)
  90. qnsid = '%s.%s' % (nsgroup, nsid)
  91. uri = daemon.connect(impl, qnsid)
  92. _PYRO_OBJS[qnsid] = str(uri)
  93. _LOGGER.info('registered %s a pyro object using group %s and id %s',
  94. object, nsgroup, nsid)
  95. return daemon
  96. def get_object_uri(qnsid):
  97. return _PYRO_OBJS[qnsid]
  98. def ns_unregister(nsid, defaultnsgroup=_MARKER, nshost=None):
  99. """unregister the object with the given nsid from the pyro name server"""
  100. nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
  101. try:
  102. nsd = locate_ns(nshost)
  103. except errors.PyroError, ex:
  104. # name server not responding
  105. _LOGGER.error('can\'t locate pyro name server: %s', ex)
  106. else:
  107. try:
  108. nsd.unregister('%s.%s' % (nsgroup, nsid))
  109. _LOGGER.info('%s unregistered from pyro name server', nsid)
  110. except errors.NamingError:
  111. _LOGGER.warning('%s not registered in pyro name server', nsid)
  112. def ns_reregister(nsid, defaultnsgroup=_MARKER, nshost=None):
  113. """reregister a pyro object into the name server. You only have to specify
  114. the name-server id of the object (though you MUST have gone through
  115. `register_object` for the given object previously).
  116. This is especially useful for long running server while the name server may
  117. have been restarted, and its records lost.
  118. """
  119. nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
  120. qnsid = '%s.%s' % (nsgroup, nsid)
  121. nsd = locate_ns(nshost)
  122. try:
  123. nsd.unregister(qnsid)
  124. except errors.NamingError:
  125. # make sure our namespace group exists
  126. try:
  127. nsd.createGroup(nsgroup)
  128. except errors.NamingError:
  129. pass
  130. nsd.register(qnsid, _PYRO_OBJS[qnsid])
  131. def ns_get_proxy(nsid, defaultnsgroup=_MARKER, nshost=None):
  132. """
  133. if nshost is None, the nameserver is found by a broadcast.
  134. """
  135. # resolve the Pyro object
  136. nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
  137. try:
  138. nsd = locate_ns(nshost)
  139. pyrouri = nsd.resolve('%s.%s' % (nsgroup, nsid))
  140. except errors.ProtocolError, ex:
  141. raise errors.PyroError(
  142. 'Could not connect to the Pyro name server (host: %s)' % nshost)
  143. except errors.NamingError:
  144. raise errors.PyroError(
  145. 'Could not get proxy for %s (not registered in Pyro), '
  146. 'you may have to restart your server-side application' % nsid)
  147. return core.getProxyForURI(pyrouri)
  148. def get_proxy(pyro_uri):
  149. """get a proxy for the passed pyro uri without using a nameserver
  150. """
  151. return core.getProxyForURI(pyro_uri)
  152. def set_pyro_log_threshold(level):
  153. pyrologger = logging.getLogger('Pyro.%s' % str(id(util.Log)))
  154. # remove handlers so only the root handler is used
  155. pyrologger.handlers = []
  156. pyrologger.setLevel(level)