Add support for tenant_id based authentication with Neutron

Keystone v3 supports non-unique project/tenant names, so
Nova should switch to using tenant ID for admin authentication.

Implements blueprint tenant-id-based-auth-for-neutron
DocImpact: Adds new flag, nova_admin_tenant_id, and deprecates
existing flag, nova_admin_tenant_name

Change-Id: I4a4ffe84fdcf98ace81fd148f096cad483aad96c
This commit is contained in:
Phil Day 2014-01-29 20:48:49 +00:00
parent d101e7215b
commit e80cf75fc0
4 changed files with 63 additions and 45 deletions

View File

@ -1470,8 +1470,14 @@
# value)
#neutron_admin_password=<None>
# Tenant name for connecting to neutron in admin context
# (string value)
# Tenant id for connecting to neutron in admin context (string
# value)
#neutron_admin_tenant_id=<None>
# DEPRECATED: Tenant name for connecting to neutron in admin
# context. This option is deprecated. Please use
# neutron_admin_tenant_id instead. Note that with Keystone V3
# tenant names may not be unique. (string value)
#neutron_admin_tenant_name=<None>
# Region name for connecting to neutron in admin context

View File

@ -17,6 +17,7 @@ from neutronclient.common import exceptions
from neutronclient.v2_0 import client as clientv20
from oslo.config import cfg
from nova.openstack.common.gettextutils import _
from nova.openstack.common import local
from nova.openstack.common import log as logging
@ -37,7 +38,13 @@ def _get_client(token=None):
params['auth_strategy'] = None
else:
params['username'] = CONF.neutron_admin_username
params['tenant_name'] = CONF.neutron_admin_tenant_name
if CONF.neutron_admin_tenant_id:
params['tenant_id'] = CONF.neutron_admin_tenant_id
else:
params['tenant_name'] = CONF.neutron_admin_tenant_name
LOG.warning(_("Using neutron_admin_tenant_name for authentication "
"is deprecated and will be removed in the next "
"release. Use neutron_admin_tenant_id instead."))
params['password'] = CONF.neutron_admin_password
params['auth_url'] = CONF.neutron_admin_auth_url
params['auth_strategy'] = CONF.neutron_auth_strategy

View File

@ -49,8 +49,13 @@ neutron_opts = [
cfg.StrOpt('neutron_admin_password',
help='Password for connecting to neutron in admin context',
secret=True),
cfg.StrOpt('neutron_admin_tenant_id',
help='Tenant id for connecting to neutron in admin context'),
cfg.StrOpt('neutron_admin_tenant_name',
help='Tenant name for connecting to neutron in admin context'),
help='DEPRECATED: Tenant name for connecting to neutron in '
'admin context. This option is deprecated. Please use '
'neutron_admin_tenant_id instead. Note that with Keystone '
'V3 tenant names may not be unique.'),
cfg.StrOpt('neutron_region_name',
help='Region name for connecting to neutron in admin context'),
cfg.StrOpt('neutron_admin_auth_url',

View File

@ -2000,59 +2000,59 @@ class TestNeutronClientForAdminScenarios(test.TestCase):
neutronv2.get_client,
my_context)
def test_get_client_for_admin(self):
def _test_get_client_for_admin(self, use_id=False, admin_context=False):
self.flags(neutron_auth_strategy=None)
self.flags(neutron_url='http://anyhost/')
self.flags(neutron_url_timeout=30)
my_context = context.RequestContext('userid', 'my_tenantid',
if use_id:
self.flags(neutron_admin_tenant_id='admin_tenant_id')
if admin_context:
my_context = context.get_admin_context()
else:
my_context = context.RequestContext('userid', 'my_tenantid',
auth_token='token')
self.mox.StubOutWithMock(client.Client, "__init__")
client.Client.__init__(
auth_url=CONF.neutron_admin_auth_url,
password=CONF.neutron_admin_password,
tenant_name=CONF.neutron_admin_tenant_name,
username=CONF.neutron_admin_username,
endpoint_url=CONF.neutron_url,
auth_strategy=None,
timeout=CONF.neutron_url_timeout,
insecure=False,
ca_cert=None).AndReturn(None)
kwargs = {
'auth_url': CONF.neutron_admin_auth_url,
'password': CONF.neutron_admin_password,
'username': CONF.neutron_admin_username,
'endpoint_url': CONF.neutron_url,
'auth_strategy': None,
'timeout': CONF.neutron_url_timeout,
'insecure': False,
'ca_cert': None}
if use_id:
kwargs['tenant_id'] = CONF.neutron_admin_tenant_id
else:
kwargs['tenant_name'] = CONF.neutron_admin_tenant_name
client.Client.__init__(**kwargs).AndReturn(None)
self.mox.ReplayAll()
# clear the cache
if hasattr(local.strong_store, 'neutron_client'):
delattr(local.strong_store, 'neutron_client')
# Note that the context is not elevated, but the True is passed in
# which will force an elevation to admin credentials even though
# the context has an auth_token.
neutronv2.get_client(my_context, True)
if admin_context:
# Note that the context does not contain a token but is
# an admin context which will force an elevation to admin
# credentials.
neutronv2.get_client(my_context)
else:
# Note that the context is not elevated, but the True is passed in
# which will force an elevation to admin credentials even though
# the context has an auth_token.
neutronv2.get_client(my_context, True)
def test_get_client_for_admin(self):
self._test_get_client_for_admin()
def test_get_client_for_admin_with_id(self):
self._test_get_client_for_admin(use_id=True)
def test_get_client_for_admin_context(self):
self._test_get_client_for_admin(admin_context=True)
self.flags(neutron_auth_strategy=None)
self.flags(neutron_url='http://anyhost/')
self.flags(neutron_url_timeout=30)
my_context = context.get_admin_context()
self.mox.StubOutWithMock(client.Client, "__init__")
client.Client.__init__(
auth_url=CONF.neutron_admin_auth_url,
password=CONF.neutron_admin_password,
tenant_name=CONF.neutron_admin_tenant_name,
username=CONF.neutron_admin_username,
endpoint_url=CONF.neutron_url,
auth_strategy=None,
timeout=CONF.neutron_url_timeout,
insecure=False,
ca_cert=None).AndReturn(None)
self.mox.ReplayAll()
# clear the cache
if hasattr(local.strong_store, 'neutron_client'):
delattr(local.strong_store, 'neutron_client')
# Note that the context does not contain a token but is
# an admin context which will force an elevation to admin
# credentials.
neutronv2.get_client(my_context)
def test_get_client_for_admin_context_with_id(self):
self._test_get_client_for_admin(use_id=True, admin_context=True)