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 20Main functions available: 21 22* `register_object` to expose arbitrary object through pyro using delegation 23 approach and register it in the nameserver. 24* `ns_unregister` unregister an object identifier from the nameserver. 25* `ns_get_proxy` get a pyro proxy from a nameserver object identifier. 26""" 27 28__docformat__ = "restructuredtext en" 29 30import logging 31import tempfile 32 33from Pyro import core, naming, errors, util, config 34 35_LOGGER = logging.getLogger('pyro') 36_MARKER = object() 37 38config.PYRO_STORAGE = tempfile.gettempdir() 39 40def ns_group_and_id(idstr, defaultnsgroup=_MARKER): 41 try: 42 nsgroup, nsid = idstr.rsplit('.', 1) 43 except ValueError: 44 if defaultnsgroup is _MARKER: 45 nsgroup = config.PYRO_NS_DEFAULTGROUP 46 else: 47 nsgroup = defaultnsgroup 48 nsid = idstr 49 if nsgroup is not None and not nsgroup.startswith(':'): 50 nsgroup = ':' + nsgroup 51 return nsgroup, nsid 52 53def host_and_port(hoststr): 54 if not hoststr: 55 return None, None 56 try: 57 hoststr, port = hoststr.split(':') 58 except ValueError: 59 port = None 60 else: 61 port = int(port) 62 return hoststr, port 63 64_DAEMONS = {} 65_PYRO_OBJS = {} 66def _get_daemon(daemonhost, start=True): 67 if not daemonhost in _DAEMONS: 68 if not start: 69 raise Exception('no daemon for %s' % daemonhost) 70 if not _DAEMONS: 71 core.initServer(banner=0) 72 host, port = host_and_port(daemonhost) 73 daemon = core.Daemon(host=host, port=port) 74 _DAEMONS[daemonhost] = daemon 75 return _DAEMONS[daemonhost] 76 77 78def locate_ns(nshost): 79 """locate and return the pyro name server to the daemon""" 80 core.initClient(banner=False) 81 return naming.NameServerLocator().getNS(*host_and_port(nshost)) 82 83 84def register_object(object, nsid, defaultnsgroup=_MARKER, 85 daemonhost=None, nshost=None, use_pyrons=True): 86 """expose the object as a pyro object and register it in the name-server 87 88 if use_pyrons is False, then the object is exposed, but no 89 attempt to register it to a pyro nameserver is made. 90 91 return the pyro daemon object 92 """ 93 nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup) 94 daemon = _get_daemon(daemonhost) 95 if use_pyrons: 96 nsd = locate_ns(nshost) 97 # make sure our namespace group exists 98 try: 99 nsd.createGroup(nsgroup) 100 except errors.NamingError: 101 pass 102 daemon.useNameServer(nsd) 103 # use Delegation approach 104 impl = core.ObjBase() 105 impl.delegateTo(object) 106 qnsid = '%s.%s' % (nsgroup, nsid) 107 uri = daemon.connect(impl, qnsid) 108 _PYRO_OBJS[qnsid] = str(uri) 109 _LOGGER.info('registered %s a pyro object using group %s and id %s', 110 object, nsgroup, nsid) 111 return daemon 112 113def get_object_uri(qnsid): 114 return _PYRO_OBJS[qnsid] 115 116def ns_unregister(nsid, defaultnsgroup=_MARKER, nshost=None): 117 """unregister the object with the given nsid from the pyro name server""" 118 nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup) 119 try: 120 nsd = locate_ns(nshost) 121 except errors.PyroError as ex: 122 # name server not responding 123 _LOGGER.error('can\'t locate pyro name server: %s', ex) 124 else: 125 try: 126 nsd.unregister('%s.%s' % (nsgroup, nsid)) 127 _LOGGER.info('%s unregistered from pyro name server', nsid) 128 except errors.NamingError: 129 _LOGGER.warning('%s not registered in pyro name server', nsid) 130 131 132def ns_reregister(nsid, defaultnsgroup=_MARKER, nshost=None): 133 """reregister a pyro object into the name server. You only have to specify 134 the name-server id of the object (though you MUST have gone through 135 `register_object` for the given object previously). 136 137 This is especially useful for long running server while the name server may 138 have been restarted, and its records lost. 139 """ 140 nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup) 141 qnsid = '%s.%s' % (nsgroup, nsid) 142 nsd = locate_ns(nshost) 143 try: 144 nsd.unregister(qnsid) 145 except errors.NamingError: 146 # make sure our namespace group exists 147 try: 148 nsd.createGroup(nsgroup) 149 except errors.NamingError: 150 pass 151 nsd.register(qnsid, _PYRO_OBJS[qnsid]) 152 153def ns_get_proxy(nsid, defaultnsgroup=_MARKER, nshost=None): 154 """ 155 if nshost is None, the nameserver is found by a broadcast. 156 """ 157 # resolve the Pyro object 158 nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup) 159 try: 160 nsd = locate_ns(nshost) 161 pyrouri = nsd.resolve('%s.%s' % (nsgroup, nsid)) 162 except errors.ProtocolError as ex: 163 raise errors.PyroError( 164 'Could not connect to the Pyro name server (host: %s)' % nshost) 165 except errors.NamingError: 166 raise errors.PyroError( 167 'Could not get proxy for %s (not registered in Pyro), ' 168 'you may have to restart your server-side application' % nsid) 169 return core.getProxyForURI(pyrouri) 170 171def get_proxy(pyro_uri): 172 """get a proxy for the passed pyro uri without using a nameserver 173 """ 174 return core.getProxyForURI(pyro_uri) 175 176def set_pyro_log_threshold(level): 177 pyrologger = logging.getLogger('Pyro.%s' % str(id(util.Log))) 178 # remove handlers so only the root handler is used 179 pyrologger.handlers = [] 180 pyrologger.setLevel(level) 181