Remove the dependancy on Mistral
The keystone utils for getting project endpoints is the last reason that we import directly from Mistral. This change copies over the relevant code that we need. Removing the dep also discovered two dependancies that we had but didn't explicitly state previously. Change-Id: If4cb4ac4ca75ea0f165196b4a0a08ea3d3a16e25
This commit is contained in:
parent
76b3e025b7
commit
9bc1f31469
@ -14,9 +14,10 @@ oslo.utils>=3.20.0 # Apache-2.0
|
||||
python-glanceclient>=2.7.0 # Apache-2.0
|
||||
python-ironicclient>=1.11.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
mistral!=2015.1.0,>=3.0.0 # Apache-2.0
|
||||
mistral-lib>=0.2.0 # Apache-2.0
|
||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||
python-ironic-inspector-client>=1.5.0 # Apache-2.0
|
||||
python-mistralclient>=3.1.0 # Apache-2.0
|
||||
Jinja2!=2.9.0,!=2.9.1,!=2.9.2,!=2.9.3,!=2.9.4,>=2.8 # BSD License (3 clause)
|
||||
python-novaclient>=9.0.0 # Apache-2.0
|
||||
passlib>=1.7.0 # BSD
|
||||
|
@ -19,13 +19,14 @@ from glanceclient.v2 import client as glanceclient
|
||||
from heatclient.v1 import client as heatclient
|
||||
import ironic_inspector_client
|
||||
from ironicclient.v1 import client as ironicclient
|
||||
from mistral.utils.openstack import keystone as keystone_utils
|
||||
from mistral_lib import actions
|
||||
from mistralclient.api import client as mistral_client
|
||||
from novaclient.client import Client as nova_client
|
||||
from swiftclient import client as swift_client
|
||||
from swiftclient import exceptions as swiftexceptions
|
||||
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import keystone as keystone_utils
|
||||
|
||||
|
||||
class TripleOAction(actions.Action):
|
||||
@ -34,7 +35,7 @@ class TripleOAction(actions.Action):
|
||||
super(TripleOAction, self).__init__()
|
||||
|
||||
def get_object_client(self, context):
|
||||
obj_ep = keystone_utils.get_endpoint_for_project('swift')
|
||||
obj_ep = keystone_utils.get_endpoint_for_project(context, 'swift')
|
||||
|
||||
kwargs = {
|
||||
'preauthurl': obj_ep.url % {'tenant_id': context.project_id},
|
||||
@ -47,7 +48,8 @@ class TripleOAction(actions.Action):
|
||||
return swift_client.Connection(**kwargs)
|
||||
|
||||
def get_baremetal_client(self, context):
|
||||
ironic_endpoint = keystone_utils.get_endpoint_for_project('ironic')
|
||||
ironic_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'ironic')
|
||||
|
||||
# FIXME(lucasagomes): Use ironicclient.get_client() instead
|
||||
# of ironicclient.Client(). Client() might cause errors since
|
||||
@ -69,7 +71,7 @@ class TripleOAction(actions.Action):
|
||||
|
||||
def get_baremetal_introspection_client(self, context):
|
||||
bmi_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
'ironic-inspector')
|
||||
context, 'ironic-inspector')
|
||||
|
||||
return ironic_inspector_client.ClientV1(
|
||||
api_version='1.2',
|
||||
@ -79,7 +81,8 @@ class TripleOAction(actions.Action):
|
||||
)
|
||||
|
||||
def get_image_client(self, context):
|
||||
glance_endpoint = keystone_utils.get_endpoint_for_project('glance')
|
||||
glance_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'glance')
|
||||
return glanceclient.Client(
|
||||
glance_endpoint.url,
|
||||
token=context.auth_token,
|
||||
@ -87,7 +90,8 @@ class TripleOAction(actions.Action):
|
||||
)
|
||||
|
||||
def get_orchestration_client(self, context):
|
||||
heat_endpoint = keystone_utils.get_endpoint_for_project('heat')
|
||||
heat_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'heat')
|
||||
|
||||
endpoint_url = keystone_utils.format_url(
|
||||
heat_endpoint.url,
|
||||
@ -102,7 +106,8 @@ class TripleOAction(actions.Action):
|
||||
)
|
||||
|
||||
def get_workflow_client(self, context):
|
||||
mistral_endpoint = keystone_utils.get_endpoint_for_project('mistral')
|
||||
mistral_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'mistral')
|
||||
|
||||
mc = mistral_client.client(auth_token=context.auth_token,
|
||||
mistral_url=mistral_endpoint.url)
|
||||
@ -110,8 +115,10 @@ class TripleOAction(actions.Action):
|
||||
return mc
|
||||
|
||||
def get_compute_client(self, context):
|
||||
keystone_endpoint = keystone_utils.get_endpoint_for_project('keystone')
|
||||
nova_endpoint = keystone_utils.get_endpoint_for_project('nova')
|
||||
keystone_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'keystone')
|
||||
nova_endpoint = keystone_utils.get_endpoint_for_project(
|
||||
context, 'nova')
|
||||
|
||||
client = nova_client(
|
||||
2,
|
||||
|
@ -118,3 +118,7 @@ class NotFound(Exception):
|
||||
|
||||
class RoleMetadataError(Exception):
|
||||
"""Role metadata is invalid"""
|
||||
|
||||
|
||||
class UnauthorizedException(Exception):
|
||||
"""Authorization failed"""
|
||||
|
@ -17,10 +17,10 @@ import zlib
|
||||
import mock
|
||||
|
||||
from ironicclient.v1 import client as ironicclient
|
||||
from mistral.utils.openstack import keystone as keystone_utils
|
||||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.tests import base as tests_base
|
||||
from tripleo_common.utils import keystone as keystone_utils
|
||||
|
||||
from swiftclient.exceptions import ClientException
|
||||
|
||||
@ -41,7 +41,7 @@ class TestActionsBase(tests_base.TestCase):
|
||||
mock_client.assert_called_once_with(
|
||||
'http://ironic/v1', max_retries=12, os_ironic_api_version='1.15',
|
||||
region_name='ironic-region', retry_interval=5, token=mock.ANY)
|
||||
mock_endpoint.assert_called_once_with('ironic')
|
||||
mock_endpoint.assert_called_once_with(mock_cxt, 'ironic')
|
||||
mock_cxt.assert_not_called()
|
||||
|
||||
def test_cache_key(self, mock_endpoint):
|
||||
|
@ -857,8 +857,7 @@ class GetProfileOfFlavorActionTest(base.TestCase):
|
||||
@mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('mistral.context.ctx')
|
||||
def test_profile_found(self, mock_ctx, mock_get_compute_client,
|
||||
def test_profile_found(self, mock_get_compute_client,
|
||||
mock_get_profile_of_flavor):
|
||||
mock_ctx = mock.MagicMock()
|
||||
mock_get_profile_of_flavor.return_value = 'compute'
|
||||
@ -870,8 +869,7 @@ class GetProfileOfFlavorActionTest(base.TestCase):
|
||||
@mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('mistral.context.ctx')
|
||||
def test_profile_not_found(self, mock_ctx, mock_get_compute_client,
|
||||
def test_profile_not_found(self, mock_get_compute_client,
|
||||
mock_get_profile_of_flavor):
|
||||
mock_ctx = mock.MagicMock()
|
||||
profile = (exception.DeriveParamsError, )
|
||||
|
122
tripleo_common/utils/keystone.py
Normal file
122
tripleo_common/utils/keystone.py
Normal file
@ -0,0 +1,122 @@
|
||||
# Copyright (c) 2013 Mirantis Inc.
|
||||
# Copyright (c) 2017 Red Hat, Inc.
|
||||
#
|
||||
# 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 keystoneclient import service_catalog as ks_service_catalog
|
||||
from keystoneclient.v3 import client as ks_client
|
||||
from keystoneclient.v3 import endpoints as ks_endpoints
|
||||
import six
|
||||
|
||||
from tripleo_common import exception
|
||||
|
||||
|
||||
def client(ctx):
|
||||
auth_url = ctx.auth_uri
|
||||
|
||||
cl = ks_client.Client(
|
||||
user_id=ctx.user_id,
|
||||
token=ctx.auth_token,
|
||||
tenant_id=ctx.project_id,
|
||||
auth_url=auth_url
|
||||
)
|
||||
|
||||
cl.management_url = auth_url
|
||||
|
||||
return cl
|
||||
|
||||
|
||||
def get_endpoint_for_project(ctx, service_name=None, service_type=None,
|
||||
region_name=None):
|
||||
if service_name is None and service_type is None:
|
||||
raise ValueError(
|
||||
"Either 'service_name' or 'service_type' must be provided."
|
||||
)
|
||||
|
||||
service_catalog = obtain_service_catalog(ctx)
|
||||
|
||||
# When region_name is not passed, first get from context as region_name
|
||||
# could be passed to rest api in http header ('X-Region-Name'). Otherwise,
|
||||
# just get region from mistral configuration.
|
||||
region = (region_name or ctx.region_name)
|
||||
|
||||
service_endpoints = service_catalog.get_endpoints(
|
||||
service_name=service_name,
|
||||
service_type=service_type,
|
||||
region_name=region
|
||||
)
|
||||
|
||||
endpoint = None
|
||||
os_actions_endpoint_type = 'public'
|
||||
|
||||
for endpoints in six.itervalues(service_endpoints):
|
||||
for ep in endpoints:
|
||||
# is V3 interface?
|
||||
if 'interface' in ep:
|
||||
interface_type = ep['interface']
|
||||
if os_actions_endpoint_type in interface_type:
|
||||
endpoint = ks_endpoints.Endpoint(
|
||||
None,
|
||||
ep,
|
||||
loaded=True
|
||||
)
|
||||
break
|
||||
# is V2 interface?
|
||||
if 'publicURL' in ep:
|
||||
endpoint_data = {
|
||||
'url': ep['publicURL'],
|
||||
'region': ep['region']
|
||||
}
|
||||
endpoint = ks_endpoints.Endpoint(
|
||||
None,
|
||||
endpoint_data,
|
||||
loaded=True
|
||||
)
|
||||
break
|
||||
|
||||
if not endpoint:
|
||||
raise RuntimeError(
|
||||
"No endpoints found [service_name=%s, service_type=%s,"
|
||||
" region_name=%s]"
|
||||
% (service_name, service_type, region)
|
||||
)
|
||||
else:
|
||||
return endpoint
|
||||
|
||||
|
||||
def obtain_service_catalog(ctx):
|
||||
token = ctx.auth_token
|
||||
|
||||
response = ctx.service_catalog
|
||||
|
||||
# Target service catalog may not be passed via API.
|
||||
if not response and ctx.is_target:
|
||||
response = client().tokens.get_token_data(
|
||||
token,
|
||||
include_catalog=True
|
||||
)['token']
|
||||
|
||||
if not response:
|
||||
raise exception.UnauthorizedException()
|
||||
|
||||
service_catalog = ks_service_catalog.ServiceCatalog.factory(response)
|
||||
|
||||
return service_catalog
|
||||
|
||||
|
||||
def format_url(url_template, values):
|
||||
# Since we can't use keystone module, we can do similar thing:
|
||||
# see https://github.com/openstack/keystone/blob/master/keystone/
|
||||
# catalog/core.py#L42-L60
|
||||
return url_template.replace('$(', '%(') % values
|
Loading…
x
Reference in New Issue
Block a user