Fix authentication of Nova client
Blazar authenticates Nova requests with trust-scoped tokens. Sometime during the Ocata cycle these requests started failing (possibly due to stricter validation in Keystone) with the error: BadRequest: Invalid input for field 'identity/password/user/password': None is not of type 'string' (HTTP 400) This commit changes how the Nova client is configured to use the token_endpoint authentication plugin combined with endpoint_override, which allows to communicate with the Nova endpoint without extra requests to Keystone. This is necessary between trust-scoped tokens cannot re-authenticate with Keystone, which happens with other authentication plugins. Change-Id: Ibb6782140f41aea5e539e11f2618b3af2628fc4c Closes-Bug: #1660564
This commit is contained in:
parent
98d4c7ddf4
commit
81b85a11af
@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from keystoneauth1 import session
|
||||
from keystoneauth1 import token_endpoint
|
||||
from novaclient import client as nova_client
|
||||
|
||||
from climate import context
|
||||
@ -32,44 +34,41 @@ class TestCNClient(tests.TestCase):
|
||||
|
||||
self.ctx = self.patch(self.context, 'current')
|
||||
self.client = self.patch(self.n_client, 'Client')
|
||||
self.patch(self.base, 'url_for').return_value = 'http://fake.com/'
|
||||
self.auth = self.patch(token_endpoint, 'Token')
|
||||
self.session = self.patch(session, 'Session')
|
||||
self.url = 'http://fake.com/'
|
||||
self.patch(self.base, 'url_for').return_value = self.url
|
||||
|
||||
self.version = '2'
|
||||
self.username = 'fake_user'
|
||||
self.api_key = self.ctx().auth_token
|
||||
self.project_id = self.ctx().project_id
|
||||
self.auth_url = 'fake_auth'
|
||||
self.mgmt_url = 'fake_mgmt'
|
||||
|
||||
def test_client_from_kwargs(self):
|
||||
self.ctx.side_effect = RuntimeError
|
||||
self.auth_token = 'fake_token'
|
||||
self.endpoint = 'fake_endpoint'
|
||||
|
||||
kwargs = {'version': self.version,
|
||||
'username': self.username,
|
||||
'api_key': self.api_key,
|
||||
'project_id': self.project_id,
|
||||
'auth_url': self.auth_url,
|
||||
'mgmt_url': self.mgmt_url}
|
||||
'endpoint_override': self.endpoint,
|
||||
'auth_token': self.auth_token}
|
||||
|
||||
self.nova.ClimateNovaClient(**kwargs)
|
||||
|
||||
self.auth.assert_called_once_with(self.endpoint, self.auth_token)
|
||||
self.session.assert_called_once_with(auth=self.auth.return_value)
|
||||
self.client.assert_called_once_with(version=self.version,
|
||||
username=self.username,
|
||||
api_key=self.api_key,
|
||||
project_id=self.project_id,
|
||||
auth_url=self.auth_url)
|
||||
endpoint_override=self.endpoint,
|
||||
session=self.session.return_value)
|
||||
|
||||
def test_client_from_ctx(self):
|
||||
|
||||
kwargs = {'version': self.version}
|
||||
|
||||
self.nova.ClimateNovaClient(**kwargs)
|
||||
|
||||
self.auth.assert_called_once_with(self.url,
|
||||
self.ctx().auth_token)
|
||||
self.session.assert_called_once_with(auth=self.auth.return_value)
|
||||
self.client.assert_called_once_with(version=self.version,
|
||||
username=self.ctx().user_name,
|
||||
api_key=None,
|
||||
project_id=self.ctx().project_id,
|
||||
auth_url='http://fake.com/')
|
||||
endpoint_override=self.url,
|
||||
session=self.session.return_value)
|
||||
|
||||
def test_getattr(self):
|
||||
# TODO(n.s.): Will be done as soon as pypi package will be updated
|
||||
|
@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from keystoneauth1 import session
|
||||
from keystoneauth1 import token_endpoint
|
||||
from novaclient import client as nova_client
|
||||
from novaclient import exceptions as nova_exception
|
||||
from novaclient.v2 import servers
|
||||
@ -50,55 +52,37 @@ class ClimateNovaClient(object):
|
||||
:param version: service client version which we will use
|
||||
:type version: str
|
||||
|
||||
:param username: username
|
||||
:type username: str
|
||||
|
||||
:param api_key: password
|
||||
:type api_key: str
|
||||
|
||||
:param auth_token: keystone auth token
|
||||
:type auth_token: str
|
||||
|
||||
:param project_id: project_id
|
||||
:type api_key: str
|
||||
|
||||
:param auth_url: auth_url
|
||||
:type auth_url: str
|
||||
|
||||
:param mgmt_url: management url
|
||||
:type mgmt_url: str
|
||||
:param endpoint_override: endpoint url which we will use
|
||||
:type endpoint_override: str
|
||||
"""
|
||||
|
||||
ctx = kwargs.pop('ctx', None)
|
||||
auth_token = kwargs.pop('auth_token', None)
|
||||
mgmt_url = kwargs.pop('mgmt_url', None)
|
||||
endpoint_override = kwargs.pop('endpoint_override', None)
|
||||
version = kwargs.pop('version', cfg.CONF.nova_client_version)
|
||||
|
||||
if ctx is None:
|
||||
try:
|
||||
ctx = context.current()
|
||||
except RuntimeError:
|
||||
pass
|
||||
kwargs.setdefault('version', cfg.CONF.nova_client_version)
|
||||
if ctx is not None:
|
||||
kwargs.setdefault('username', ctx.user_name)
|
||||
kwargs.setdefault('api_key', None)
|
||||
kwargs.setdefault('project_id', ctx.project_id)
|
||||
kwargs.setdefault('auth_url', base.url_for(
|
||||
ctx.service_catalog, CONF.identity_service))
|
||||
|
||||
auth_token = auth_token or ctx.auth_token
|
||||
mgmt_url = mgmt_url or base.url_for(ctx.service_catalog,
|
||||
CONF.compute_service)
|
||||
if not kwargs.get('auth_url', None):
|
||||
# NOTE(scroiset): novaclient v2.17.0 support only Identity API v2.0
|
||||
auth_url = "%s://%s:%s/v2.0" % (CONF.os_auth_protocol,
|
||||
CONF.os_auth_host,
|
||||
CONF.os_auth_port)
|
||||
kwargs['auth_url'] = auth_url
|
||||
endpoint_override = endpoint_override or \
|
||||
base.url_for(ctx.service_catalog,
|
||||
CONF.compute_service)
|
||||
|
||||
auth = token_endpoint.Token(endpoint_override,
|
||||
auth_token)
|
||||
sess = session.Session(auth=auth)
|
||||
|
||||
kwargs.setdefault('endpoint_override', endpoint_override)
|
||||
kwargs.setdefault('session', sess)
|
||||
kwargs.setdefault('version', version)
|
||||
self.nova = nova_client.Client(**kwargs)
|
||||
self.nova.client.auth_token = auth_token
|
||||
self.nova.client.management_url = mgmt_url
|
||||
|
||||
self.nova.servers = ServerManager(self.nova)
|
||||
|
||||
@ -136,8 +120,5 @@ class NovaClientWrapper(object):
|
||||
@property
|
||||
def nova(self):
|
||||
ctx = context.current()
|
||||
nova = ClimateNovaClient(username=ctx.user_name,
|
||||
api_key=None,
|
||||
project_id=ctx.project_id,
|
||||
ctx=ctx)
|
||||
nova = ClimateNovaClient(ctx=ctx)
|
||||
return nova
|
||||
|
Loading…
Reference in New Issue
Block a user