Add transport aliases

We need to support deprecated transport driver configurations like:

 rpc_backend = nova.rpc.impl_kombu

i.e. 'nova.rpc.impl_kombu' is a deprecated alias for 'rabbit'.

Initially, we supported this by adding the aliases to each project's
setup.cfg:

oslo.messaging.drivers =
    nova.rpc.impl_kombu = oslo.messaging._drivers.impl_rabbit:RabbitDriver

However, this means that code like this:

  url = str(TransportURL(conf))

generates a bogus URL string like:

  nova.rpc.impl_kombu://...

We need to apply these transport aliases when we load drivers, but also
when we create transport URLs from configuration containing potentially
deprecated aliases.

To enable that, add an aliases parameter to TransportURL(),
TransportURL.parse() and get_transport().

blueprint: transport-aliases
Change-Id: Ifce68ff62746c2a363c719417a2bd0a78ee025dd
This commit is contained in:
Mark McLoughlin 2013-11-29 21:55:45 +00:00 committed by Ben Nemec
parent f9ab2e105f
commit 5b8fbdcad2
3 changed files with 90 additions and 27 deletions

View File

@ -123,7 +123,7 @@ class DriverLoadFailure(exceptions.MessagingException):
self.ex = ex
def get_transport(conf, url=None, allowed_remote_exmods=[]):
def get_transport(conf, url=None, allowed_remote_exmods=[], aliases=None):
"""A factory method for Transport objects.
This method will construct a Transport object from transport configuration
@ -150,12 +150,14 @@ def get_transport(conf, url=None, allowed_remote_exmods=[]):
transport will deserialize remote exceptions
from
:type allowed_remote_exmods: list
:param aliases: A map of transport alias to transport name
:type aliases: dict
"""
conf.register_opts(_transport_opts)
if not isinstance(url, TransportURL):
url = url or conf.transport_url
parsed = TransportURL.parse(conf, url)
parsed = TransportURL.parse(conf, url, aliases)
if not parsed.transport:
raise InvalidTransportURL(url, 'No scheme specified in "%s"' % url)
url = parsed
@ -220,9 +222,12 @@ class TransportURL(object):
:type virtual_host: str
:param hosts: a list of TransportHost objects
:type hosts: list
:param aliases: A map of transport alias to transport name
:type aliases: dict
"""
def __init__(self, conf, transport=None, virtual_host=None, hosts=None):
def __init__(self, conf, transport=None, virtual_host=None, hosts=None,
aliases=None):
self.conf = conf
self.conf.register_opts(_transport_opts)
self._transport = transport
@ -231,13 +236,18 @@ class TransportURL(object):
self.hosts = []
else:
self.hosts = hosts
if aliases is None:
self.aliases = {}
else:
self.aliases = aliases
@property
def transport(self):
if self._transport is None:
return self.conf.rpc_backend
transport = self.conf.rpc_backend
else:
return self._transport
transport = self._transport
return self.aliases.get(transport, transport)
@transport.setter
def transport(self, value):
@ -300,7 +310,7 @@ class TransportURL(object):
return url
@classmethod
def parse(cls, conf, url):
def parse(cls, conf, url, aliases=None):
"""Parse an url.
Assuming a URL takes the form of:
@ -337,10 +347,12 @@ class TransportURL(object):
:type conf: oslo.config.cfg.ConfigOpts
:param url: The URL to parse
:type url: str
:param aliases: A map of transport alias to transport name
:type aliases: dict
:returns: A TransportURL
"""
if not url:
return cls(conf)
return cls(conf, aliases=aliases)
# FIXME(flaper87): Not PY3K compliant
if not isinstance(url, basestring):
@ -402,4 +414,4 @@ class TransportURL(object):
username=username,
password=password))
return cls(conf, url.scheme, virtual_host, hosts)
return cls(conf, url.scheme, virtual_host, hosts, aliases)

View File

@ -54,39 +54,63 @@ class GetTransportTestCase(test_utils.BaseTestCase):
scenarios = [
('rpc_backend',
dict(url=None, transport_url=None, rpc_backend='testbackend',
control_exchange=None, allowed=None,
control_exchange=None, allowed=None, aliases=None,
expect=dict(backend='testbackend',
exchange=None,
url='testbackend:',
allowed=[]))),
('transport_url',
dict(url=None, transport_url='testtransport:', rpc_backend=None,
control_exchange=None, allowed=None,
control_exchange=None, allowed=None, aliases=None,
expect=dict(backend='testtransport',
exchange=None,
url='testtransport:',
allowed=[]))),
('url_param',
dict(url='testtransport:', transport_url=None, rpc_backend=None,
control_exchange=None, allowed=None,
control_exchange=None, allowed=None, aliases=None,
expect=dict(backend='testtransport',
exchange=None,
url='testtransport:',
allowed=[]))),
('control_exchange',
dict(url=None, transport_url=None, rpc_backend='testbackend',
control_exchange='testexchange', allowed=None,
control_exchange='testexchange', allowed=None, aliases=None,
expect=dict(backend='testbackend',
exchange='testexchange',
url='testbackend:',
allowed=[]))),
('allowed_remote_exmods',
dict(url=None, transport_url=None, rpc_backend='testbackend',
control_exchange=None, allowed=['foo', 'bar'],
control_exchange=None, allowed=['foo', 'bar'], aliases=None,
expect=dict(backend='testbackend',
exchange=None,
url='testbackend:',
allowed=['foo', 'bar']))),
('rpc_backend_aliased',
dict(url=None, transport_url=None, rpc_backend='testfoo',
control_exchange=None, allowed=None,
aliases=dict(testfoo='testbackend'),
expect=dict(backend='testbackend',
exchange=None,
url='testbackend:',
allowed=[]))),
('transport_url_aliased',
dict(url=None, transport_url='testfoo:', rpc_backend=None,
control_exchange=None, allowed=None,
aliases=dict(testfoo='testtransport'),
expect=dict(backend='testtransport',
exchange=None,
url='testtransport:',
allowed=[]))),
('url_param_aliased',
dict(url='testfoo:', transport_url=None, rpc_backend=None,
control_exchange=None, allowed=None,
aliases=dict(testfoo='testtransport'),
expect=dict(backend='testtransport',
exchange=None,
url='testtransport:',
allowed=[]))),
]
def setUp(self):
@ -119,6 +143,8 @@ class GetTransportTestCase(test_utils.BaseTestCase):
kwargs = dict(url=self.url)
if self.allowed is not None:
kwargs['allowed_remote_exmods'] = self.allowed
if self.aliases is not None:
kwargs['aliases'] = self.aliases
transport = messaging.get_transport(self.conf, **kwargs)
self.assertIsNotNone(transport)

View File

@ -27,51 +27,54 @@ class TestParseURL(test_utils.BaseTestCase):
scenarios = [
('transport',
dict(url='foo:',
dict(url='foo:', aliases=None,
expect=dict(transport='foo'))),
('transport_aliased',
dict(url='bar:', aliases=dict(bar='foo'),
expect=dict(transport='foo'))),
('virtual_host_slash',
dict(url='foo:////',
dict(url='foo:////', aliases=None,
expect=dict(transport='foo', virtual_host='/'))),
('virtual_host',
dict(url='foo:///bar',
dict(url='foo:///bar', aliases=None,
expect=dict(transport='foo', virtual_host='bar'))),
('host',
dict(url='foo://host/bar',
dict(url='foo://host/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(host='host'),
]))),
('ipv6_host',
dict(url='foo://[ffff::1]/bar',
dict(url='foo://[ffff::1]/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(host='ffff::1'),
]))),
('port',
dict(url='foo://host:1234/bar',
dict(url='foo://host:1234/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(host='host', port=1234),
]))),
('ipv6_port',
dict(url='foo://[ffff::1]:1234/bar',
dict(url='foo://[ffff::1]:1234/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(host='ffff::1', port=1234),
]))),
('username',
dict(url='foo://u@host:1234/bar',
dict(url='foo://u@host:1234/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(host='host', port=1234, username='u'),
]))),
('password',
dict(url='foo://u:p@host:1234/bar',
dict(url='foo://u:p@host:1234/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
@ -79,14 +82,14 @@ class TestParseURL(test_utils.BaseTestCase):
username='u', password='p'),
]))),
('creds_no_host',
dict(url='foo://u:p@/bar',
dict(url='foo://u:p@/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
dict(username='u', password='p'),
]))),
('multi_host',
dict(url='foo://u:p@host1:1234,host2:4321/bar',
dict(url='foo://u:p@host1:1234,host2:4321/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
@ -95,7 +98,7 @@ class TestParseURL(test_utils.BaseTestCase):
dict(host='host2', port=4321),
]))),
('multi_creds',
dict(url='foo://u1:p1@host1:1234,u2:p2@host2:4321/bar',
dict(url='foo://u1:p1@host1:1234,u2:p2@host2:4321/bar', aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
@ -106,6 +109,7 @@ class TestParseURL(test_utils.BaseTestCase):
]))),
('multi_creds_ipv6',
dict(url='foo://u1:p1@[ffff::1]:1234,u2:p2@[ffff::2]:4321/bar',
aliases=None,
expect=dict(transport='foo',
virtual_host='bar',
hosts=[
@ -123,7 +127,7 @@ class TestParseURL(test_utils.BaseTestCase):
def test_parse_url(self):
self.config(rpc_backend=None)
url = messaging.TransportURL.parse(self.conf, self.url)
url = messaging.TransportURL.parse(self.conf, self.url, self.aliases)
hosts = []
for host in self.expect.get('hosts', []):
@ -147,18 +151,35 @@ class TestFormatURL(test_utils.BaseTestCase):
transport=None,
virtual_host=None,
hosts=[],
aliases=None,
expected='testbackend:///')),
('rpc_backend_aliased',
dict(rpc_backend='testfoo',
transport=None,
virtual_host=None,
hosts=[],
aliases=dict(testfoo='testbackend'),
expected='testbackend:///')),
('transport',
dict(rpc_backend=None,
transport='testtransport',
virtual_host=None,
hosts=[],
aliases=None,
expected='testtransport:///')),
('transport_aliased',
dict(rpc_backend=None,
transport='testfoo',
virtual_host=None,
hosts=[],
aliases=dict(testfoo='testtransport'),
expected='testtransport:///')),
('virtual_host',
dict(rpc_backend=None,
transport='testtransport',
virtual_host='/vhost',
hosts=[],
aliases=None,
expected='testtransport:////vhost')),
('host',
dict(rpc_backend=None,
@ -170,6 +191,7 @@ class TestFormatURL(test_utils.BaseTestCase):
username='bob',
password='secret'),
],
aliases=None,
expected='testtransport://bob:secret@host:10//')),
('multi_host',
dict(rpc_backend=None,
@ -185,6 +207,7 @@ class TestFormatURL(test_utils.BaseTestCase):
username='b2',
password='s2'),
],
aliases=None,
expected='testtransport://b1:s1@h1:1000,b2:s2@h2:2000/')),
('quoting',
dict(rpc_backend=None,
@ -196,6 +219,7 @@ class TestFormatURL(test_utils.BaseTestCase):
username='b$',
password='s&'),
],
aliases=None,
expected='testtransport://b%24:s%26@host:10//%24')),
]
@ -216,6 +240,7 @@ class TestFormatURL(test_utils.BaseTestCase):
url = messaging.TransportURL(self.conf,
self.transport,
self.virtual_host,
hosts)
hosts,
self.aliases)
self.assertEqual(str(url), self.expected)