Use ksa adapter for neutron client

nova.network.neutronv2.api.get_client now uses the common
get_ksa_adapter utility to create an Adapter from common keystoneauth1
configuration options if the legacy [neutron] config option ``url`` is
not specified.

As part of blueprint use-ksa-adapter-for-endpoints, this provides a
consistent mechanism for endpoint communication from Nova.

Change-Id: I41724a612a5f3eabd504f3eaa9d2f9d141ca3f69
Partial-Implements: bp use-ksa-adapter-for-endpoints
This commit is contained in:
Eric Fried 2017-10-05 15:00:08 -05:00
parent 9519601401
commit 6cde77ebba
4 changed files with 98 additions and 25 deletions

View File

@ -16,6 +16,10 @@
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from nova.conf import utils as confutils
DEFAULT_SERVICE_TYPE = 'network'
NEUTRON_GROUP = 'neutron'
neutron_group = cfg.OptGroup(
@ -27,7 +31,15 @@ Configuration options for neutron (network connectivity as a service).
neutron_opts = [
cfg.URIOpt('url',
default='http://127.0.0.1:9696',
sample_default='http://127.0.0.1:9696',
deprecated_for_removal=True,
deprecated_since='17.0.0',
deprecated_reason='Endpoint lookup uses the service catalog via '
'common keystoneauth1 Adapter configuration '
'options. In the current release, "url" will '
'override this behavior, but will be ignored and/or '
'removed in a future release. To achieve the same '
'result, use the endpoint_override option instead.',
help="""
This option specifies the URL for connecting to Neutron.
@ -36,18 +48,6 @@ Possible values:
* Any valid URL that points to the Neutron API service is appropriate here.
This typically matches the URL returned for the 'network' service type
from the Keystone service catalog.
"""),
cfg.StrOpt('region_name',
default='RegionOne',
help="""
Region name for connecting to Neutron in admin context.
This option is used in multi-region setups. If there are two Neutron
servers running in two regions in two different machines, then two
services need to be created in Keystone with two different regions and
associate corresponding endpoints to those services. When requests are made
to Keystone, the Keystone service uses the region_name to determine the
region the request is coming from.
"""),
cfg.StrOpt('ovs_bridge',
default='br-int',
@ -111,8 +111,11 @@ ALL_OPTS = (neutron_opts + metadata_proxy_opts)
def register_opts(conf):
conf.register_group(neutron_group)
conf.register_opts(ALL_OPTS, group=neutron_group)
ks_loading.register_session_conf_options(conf, NEUTRON_GROUP)
ks_loading.register_auth_conf_options(conf, NEUTRON_GROUP)
# NOTE(efried): We don't pass `url` as a deprecated opt because that would
# make CONF.neutron.url indistinguishable from
# CONF.neutron.endpoint_override in the code, and we need to be able to use
# the former to trigger the legacy behavior.
confutils.register_ksa_opts(conf, neutron_group, DEFAULT_SERVICE_TYPE)
def list_opts():
@ -123,5 +126,6 @@ def list_opts():
ks_loading.get_auth_common_conf_options() +
ks_loading.get_auth_plugin_conf_options('password') +
ks_loading.get_auth_plugin_conf_options('v2password') +
ks_loading.get_auth_plugin_conf_options('v3password'))
ks_loading.get_auth_plugin_conf_options('v3password') +
confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE))
}

View File

@ -41,6 +41,7 @@ from nova.pci import whitelist as pci_whitelist
from nova.policies import servers as servers_policies
from nova import profiler
from nova import service_auth
from nova import utils
CONF = nova.conf.CONF
@ -159,13 +160,35 @@ def get_client(context, admin=False):
# an admin token so log an error
raise exception.Unauthorized()
return ClientWrapper(
clientv20.Client(session=_SESSION,
auth=auth_plugin,
endpoint_override=CONF.neutron.url,
region_name=CONF.neutron.region_name,
global_request_id=context.global_id),
admin=admin or context.is_admin)
client_args = dict(session=_SESSION,
auth=auth_plugin,
global_request_id=context.global_request_id)
if CONF.neutron.url:
# TODO(efried): Remove in Rocky
client_args = dict(client_args,
endpoint_override=CONF.neutron.url,
# NOTE(efried): The legacy behavior was to default
# region_name in the conf.
region_name=CONF.neutron.region_name or 'RegionOne')
else:
# The new way
# NOTE(efried): We build an adapter
# to pull conf options
# to pass to neutronclient
# which uses them to build an Adapter.
# This should be unwound at some point.
adap = utils.get_ksa_adapter(
'network', ksa_auth=auth_plugin, ksa_session=_SESSION)
client_args = dict(client_args,
service_type=adap.service_type,
service_name=adap.service_name,
interface=adap.interface,
region_name=adap.region_name,
endpoint_override=adap.endpoint_override)
return ClientWrapper(clientv20.Client(**client_args),
admin=admin or context.is_admin)
def _is_not_duplicate(item, items, items_list_name, instance):

View File

@ -122,6 +122,36 @@ class TestNeutronClient(test.NoDBTestCase):
super(TestNeutronClient, self).setUp()
neutronapi.reset_state()
def test_ksa_adapter_loading_defaults(self):
"""No 'url' triggers ksa loading path with defaults."""
my_context = context.RequestContext('userid',
uuids.my_tenant,
auth_token='token')
cl = neutronapi.get_client(my_context)
self.assertEqual('network', cl.httpclient.service_type)
self.assertIsNone(cl.httpclient.service_name)
self.assertEqual(['internal', 'public'], cl.httpclient.interface)
self.assertIsNone(cl.httpclient.region_name)
self.assertIsNone(cl.httpclient.endpoint_override)
def test_ksa_adapter_loading(self):
"""Test ksa loading path with specified values."""
self.flags(group='neutron',
service_type='st',
service_name='sn',
valid_interfaces='admin',
region_name='RegionTwo',
endpoint_override='eo')
my_context = context.RequestContext('userid',
uuids.my_tenant,
auth_token='token')
cl = neutronapi.get_client(my_context)
self.assertEqual('st', cl.httpclient.service_type)
self.assertEqual('sn', cl.httpclient.service_name)
self.assertEqual(['admin'], cl.httpclient.interface)
self.assertEqual('RegionTwo', cl.httpclient.region_name)
self.assertEqual('eo', cl.httpclient.endpoint_override)
def test_withtoken(self):
self.flags(url='http://anyhost/', group='neutron')
self.flags(timeout=30, group='neutron')
@ -131,8 +161,9 @@ class TestNeutronClient(test.NoDBTestCase):
cl = neutronapi.get_client(my_context)
self.assertEqual(CONF.neutron.url, cl.httpclient.endpoint_override)
self.assertEqual(my_context.auth_token,
cl.httpclient.auth.auth_token)
# Specifying 'url' defaults 'region_name'
self.assertEqual('RegionOne', cl.httpclient.region_name)
self.assertEqual(my_context.auth_token, cl.httpclient.auth.auth_token)
self.assertEqual(CONF.neutron.timeout, cl.httpclient.session.timeout)
def test_withouttoken(self):

View File

@ -0,0 +1,15 @@
---
upgrade:
- |
Nova now uses keystoneauth1 configuration to set up communication with the
network service. Use keystoneauth1 loading parameters for Adapter setup in
the ``[neutron]`` conf section (auth and Session options continue to work
as before). Of note:
* Legacy option ``url`` is deprecated and replaced by
``endpoint_override``. This should not need to be specified if an
appropriate service catalog entry exists for the network service.
* When ``url`` is not used, ``region_name`` no longer defaults to
``RegionOne``.
* In Queens, specifying ``url`` will trigger the legacy behavior. The
``url`` option will be removed in Rocky.