Add service_token for nova-cinder interaction
Service token will be passed along with user token to communicate with services when dealing with long running tasks like live migration. This change addresses adding service_token to the request when nova requests cinder session to interact with cinder. Change-Id: I51eb0a8937fa39a2e5dafb1ad915e7113ea61f72 Implements: blueprint use-service-tokens
This commit is contained in:
parent
45f14c2018
commit
9e54b29c4f
@ -60,6 +60,7 @@ from nova.conf import remote_debug
|
|||||||
from nova.conf import scheduler
|
from nova.conf import scheduler
|
||||||
from nova.conf import serial_console
|
from nova.conf import serial_console
|
||||||
from nova.conf import service
|
from nova.conf import service
|
||||||
|
from nova.conf import service_token
|
||||||
from nova.conf import servicegroup
|
from nova.conf import servicegroup
|
||||||
from nova.conf import spice
|
from nova.conf import spice
|
||||||
from nova.conf import ssl
|
from nova.conf import ssl
|
||||||
@ -114,6 +115,7 @@ rdp.register_opts(CONF)
|
|||||||
scheduler.register_opts(CONF)
|
scheduler.register_opts(CONF)
|
||||||
serial_console.register_opts(CONF)
|
serial_console.register_opts(CONF)
|
||||||
service.register_opts(CONF)
|
service.register_opts(CONF)
|
||||||
|
service_token.register_opts(CONF)
|
||||||
servicegroup.register_opts(CONF)
|
servicegroup.register_opts(CONF)
|
||||||
spice.register_opts(CONF)
|
spice.register_opts(CONF)
|
||||||
ssl.register_opts(CONF)
|
ssl.register_opts(CONF)
|
||||||
|
66
nova/conf/service_token.py
Normal file
66
nova/conf/service_token.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
SERVICE_USER_GROUP = 'service_user'
|
||||||
|
|
||||||
|
service_user = cfg.OptGroup(
|
||||||
|
SERVICE_USER_GROUP,
|
||||||
|
title = 'Service token authentication type options',
|
||||||
|
help = """
|
||||||
|
Configuration options for service to service authentication using a service
|
||||||
|
token. These options allow to send a service token along with the
|
||||||
|
user's token when contacting external REST APIs.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
service_user_opts = [
|
||||||
|
cfg.BoolOpt('send_service_user_token',
|
||||||
|
default=False,
|
||||||
|
help="""
|
||||||
|
When True, if sending a user token to an REST API, also send a service token.
|
||||||
|
|
||||||
|
Nova often reuses the user token provided to the nova-api to talk to other
|
||||||
|
REST APIs, such as Cinder. It is possible that while the
|
||||||
|
user token was valid when the request was made to Nova, the token may expire
|
||||||
|
before it reaches the other service. To avoid any failures, and to
|
||||||
|
make it clear it is Nova calling the service on the users behalf, we include
|
||||||
|
a server token along with the user token. Should the user's token have
|
||||||
|
expired, a valid service token ensures the REST API request will still be
|
||||||
|
accepted by the keystone middleware.
|
||||||
|
|
||||||
|
This feature is currently experimental, and as such is turned off by default
|
||||||
|
while full testing and performance tuning of this feature is completed.
|
||||||
|
"""),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def register_opts(conf):
|
||||||
|
conf.register_group(service_user)
|
||||||
|
conf.register_opts(service_user_opts, group=service_user)
|
||||||
|
|
||||||
|
ks_loading.register_session_conf_options(conf, SERVICE_USER_GROUP)
|
||||||
|
ks_loading.register_auth_conf_options(conf, SERVICE_USER_GROUP)
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return {
|
||||||
|
service_user: (
|
||||||
|
service_user_opts +
|
||||||
|
ks_loading.get_session_conf_options() +
|
||||||
|
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'))
|
||||||
|
}
|
39
nova/service_auth.py
Normal file
39
nova/service_auth.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
|
from keystoneauth1 import service_token
|
||||||
|
|
||||||
|
import nova.conf
|
||||||
|
|
||||||
|
|
||||||
|
CONF = nova.conf.CONF
|
||||||
|
|
||||||
|
_SERVICE_AUTH = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_auth_plugin(context):
|
||||||
|
user_auth = context.get_auth_plugin()
|
||||||
|
|
||||||
|
if CONF.service_user.send_service_user_token:
|
||||||
|
global _SERVICE_AUTH
|
||||||
|
if not _SERVICE_AUTH:
|
||||||
|
_SERVICE_AUTH = ks_loading.load_auth_from_conf_options(
|
||||||
|
CONF,
|
||||||
|
group=
|
||||||
|
nova.conf.service_token.SERVICE_USER_GROUP)
|
||||||
|
return service_token.ServiceTokenAuthWrapper(
|
||||||
|
user_auth=user_auth,
|
||||||
|
service_auth=_SERVICE_AUTH)
|
||||||
|
|
||||||
|
return user_auth
|
47
nova/tests/unit/test_service_auth.py
Normal file
47
nova/tests/unit/test_service_auth.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
|
from keystoneauth1 import service_token
|
||||||
|
import mock
|
||||||
|
|
||||||
|
import nova.conf
|
||||||
|
from nova import context
|
||||||
|
from nova import service_auth
|
||||||
|
from nova import test
|
||||||
|
|
||||||
|
|
||||||
|
CONF = nova.conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceAuthTestCase(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ServiceAuthTestCase, self).setUp()
|
||||||
|
self.ctx = context.RequestContext('fake', 'fake')
|
||||||
|
|
||||||
|
@mock.patch.object(ks_loading, 'load_auth_from_conf_options')
|
||||||
|
def test_get_auth_plugin_no_wraps(self, mock_load):
|
||||||
|
context = mock.MagicMock()
|
||||||
|
context.get_auth_plugin.return_value = "fake"
|
||||||
|
|
||||||
|
result = service_auth.get_auth_plugin(context)
|
||||||
|
|
||||||
|
self.assertEqual("fake", result)
|
||||||
|
mock_load.assert_not_called()
|
||||||
|
|
||||||
|
def test_get_auth_plugin_wraps(self):
|
||||||
|
self.flags(send_service_user_token=True, group='service_user')
|
||||||
|
|
||||||
|
result = service_auth.get_auth_plugin(self.ctx)
|
||||||
|
|
||||||
|
self.assertIsInstance(result, service_token.ServiceTokenAuthWrapper)
|
@ -39,6 +39,7 @@ from nova import exception
|
|||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
from nova.i18n import _LE
|
from nova.i18n import _LE
|
||||||
from nova.i18n import _LW
|
from nova.i18n import _LW
|
||||||
|
from nova import service_auth
|
||||||
|
|
||||||
|
|
||||||
CONF = nova.conf.CONF
|
CONF = nova.conf.CONF
|
||||||
@ -65,7 +66,7 @@ def cinderclient(context):
|
|||||||
url = None
|
url = None
|
||||||
endpoint_override = None
|
endpoint_override = None
|
||||||
|
|
||||||
auth = context.get_auth_plugin()
|
auth = service_auth.get_auth_plugin(context)
|
||||||
service_type, service_name, interface = CONF.cinder.catalog_info.split(':')
|
service_type, service_name, interface = CONF.cinder.catalog_info.split(':')
|
||||||
|
|
||||||
service_parameters = {'service_type': service_type,
|
service_parameters = {'service_type': service_type,
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added support for Keystone middleware feature where if service token is
|
||||||
|
sent along with the user token, then it will ignore the expiration of user
|
||||||
|
token. This helps deal with issues of user tokens expiring during long
|
||||||
|
running operations, such as live-migration where nova tries to access
|
||||||
|
Cinder at the end of the operation using the user token that has expired.
|
||||||
|
In order to use this functionality a service user needs to be created.
|
||||||
|
Add service user configurations in ``nova.conf`` under
|
||||||
|
``service_user`` group and set ``send_service_user_token`` flag to
|
||||||
|
``True``. The minimum Keytone API version 3.8 and Keystone middleware
|
||||||
|
version 4.12.0 is required to use this functionality.
|
||||||
|
This only currently works with nova - cinder API interactions.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user