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:
Pushkar Umaranikar 2016-11-14 22:31:58 +00:00 committed by Sarafraj Singh
parent 45f14c2018
commit 9e54b29c4f
6 changed files with 170 additions and 1 deletions

View File

@ -60,6 +60,7 @@ from nova.conf import remote_debug
from nova.conf import scheduler
from nova.conf import serial_console
from nova.conf import service
from nova.conf import service_token
from nova.conf import servicegroup
from nova.conf import spice
from nova.conf import ssl
@ -114,6 +115,7 @@ rdp.register_opts(CONF)
scheduler.register_opts(CONF)
serial_console.register_opts(CONF)
service.register_opts(CONF)
service_token.register_opts(CONF)
servicegroup.register_opts(CONF)
spice.register_opts(CONF)
ssl.register_opts(CONF)

View 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
View 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

View 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)

View File

@ -39,6 +39,7 @@ from nova import exception
from nova.i18n import _
from nova.i18n import _LE
from nova.i18n import _LW
from nova import service_auth
CONF = nova.conf.CONF
@ -65,7 +66,7 @@ def cinderclient(context):
url = 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_parameters = {'service_type': service_type,

View File

@ -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.