[cfapi] Use muranoclient to access murano packages
Previously service broker queried murano db instead of using python-muranoclient to make REST API calls. It's caused some problems, e.g. service broker and GLARE couldn't work simultaneously. This commit improves creation of muranoclient in cfapi, adds artifacts-clients if package_service is set to glare and enables cfapi to query keystone in case respective urls are not provided. Co-Authored-By: Kirill Zaitsev <k.zaitsev@me.com> Change-Id: Ib87f287434eb6a5df4e3f369e5d774c780e7200a Closes-Bug: #1543986
This commit is contained in:
committed by
Nikolay Starodubtsev
parent
d911efe7a9
commit
1e0097d843
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
import keystoneclient
|
||||||
from keystoneclient.auth.identity import v3
|
from keystoneclient.auth.identity import v3
|
||||||
from keystoneclient import exceptions
|
from keystoneclient import exceptions
|
||||||
from keystoneclient import session as ks_session
|
from keystoneclient import session as ks_session
|
||||||
@@ -55,8 +56,30 @@ class ExternalContextMiddleware(wsgi.Middleware):
|
|||||||
password_auth = v3.Password(**kwargs)
|
password_auth = v3.Password(**kwargs)
|
||||||
session = ks_session.Session(auth=password_auth)
|
session = ks_session.Session(auth=password_auth)
|
||||||
|
|
||||||
|
self._query_endpoints(password_auth, session)
|
||||||
|
|
||||||
return session.get_token()
|
return session.get_token()
|
||||||
|
|
||||||
|
def _query_endpoints(self, auth, session):
|
||||||
|
if not hasattr(self, '_murano_endpoint'):
|
||||||
|
try:
|
||||||
|
self._murano_endpoint = auth.get_endpoint(
|
||||||
|
session, 'application-catalog')
|
||||||
|
except keystoneclient.exceptions.EndpointNotFound:
|
||||||
|
pass
|
||||||
|
if not hasattr(self, '_glare_endpoint'):
|
||||||
|
try:
|
||||||
|
self._glare_endpoint = auth.get_endpoint(
|
||||||
|
session, 'artifact')
|
||||||
|
except keystoneclient.exceptions.EndpointNotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_endpoints(self):
|
||||||
|
return {
|
||||||
|
'murano': getattr(self, '_murano_endpoint', None),
|
||||||
|
'glare': getattr(self, '_glare_endpoint', None),
|
||||||
|
}
|
||||||
|
|
||||||
def process_request(self, req):
|
def process_request(self, req):
|
||||||
|
|
||||||
"""Get keystone token for external request
|
"""Get keystone token for external request
|
||||||
@@ -72,6 +95,7 @@ class ExternalContextMiddleware(wsgi.Middleware):
|
|||||||
user, password = credentials.split(':', 2)
|
user, password = credentials.split(':', 2)
|
||||||
req.headers['X-Auth-Token'] = self.get_keystone_token(user,
|
req.headers['X-Auth-Token'] = self.get_keystone_token(user,
|
||||||
password)
|
password)
|
||||||
|
req.endpoints = self.get_endpoints()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
msg = _("Authorization required")
|
msg = _("Authorization required")
|
||||||
LOG.warning(msg)
|
LOG.warning(msg)
|
||||||
|
|||||||
@@ -15,16 +15,17 @@
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import muranoclient.client as client
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
from webob import response
|
from webob import response
|
||||||
|
|
||||||
from murano.common.i18n import _LI, _LW
|
from murano.common.i18n import _LI, _LW
|
||||||
|
from murano.common import auth_utils # noqa
|
||||||
from murano.common import wsgi
|
from murano.common import wsgi
|
||||||
from murano.db.catalog import api as db_api
|
|
||||||
from murano.db.services import cf_connections as db_cf
|
from murano.db.services import cf_connections as db_cf
|
||||||
|
import muranoclient.client as muranoclient
|
||||||
|
from muranoclient.glance import client as glare_client
|
||||||
|
|
||||||
|
|
||||||
cfapi_opts = [
|
cfapi_opts = [
|
||||||
@@ -57,7 +58,7 @@ class Controller(object):
|
|||||||
srv['bindable'] = True
|
srv['bindable'] = True
|
||||||
srv['tags'] = []
|
srv['tags'] = []
|
||||||
for tag in package.tags:
|
for tag in package.tags:
|
||||||
srv['tags'].append(tag.name)
|
srv['tags'].append(tag)
|
||||||
plan = {'id': package.id + '-1',
|
plan = {'id': package.id + '-1',
|
||||||
'name': 'default',
|
'name': 'default',
|
||||||
'description': 'Default plan for the service {name}'.format(
|
'description': 'Default plan for the service {name}'.format(
|
||||||
@@ -81,9 +82,10 @@ class Controller(object):
|
|||||||
|
|
||||||
def list(self, req):
|
def list(self, req):
|
||||||
|
|
||||||
packages = db_api.package_search({'type': 'application'},
|
token = req.headers['X-Auth-Token']
|
||||||
req.context,
|
m_cli = _get_muranoclient(token, req)
|
||||||
catalog=True)
|
kwargs = {'type': 'application'}
|
||||||
|
packages = m_cli.packages.filter(**kwargs)
|
||||||
services = []
|
services = []
|
||||||
for package in packages:
|
for package in packages:
|
||||||
services.append(self._package_to_service(package))
|
services.append(self._package_to_service(package))
|
||||||
@@ -124,7 +126,7 @@ class Controller(object):
|
|||||||
tenant_name=tenant))
|
tenant_name=tenant))
|
||||||
|
|
||||||
token = req.headers['X-Auth-Token']
|
token = req.headers['X-Auth-Token']
|
||||||
m_cli = muranoclient(token)
|
m_cli = _get_muranoclient(token, req)
|
||||||
try:
|
try:
|
||||||
environment_id = db_cf.get_environment_for_space(space_guid)
|
environment_id = db_cf.get_environment_for_space(space_guid)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -136,7 +138,7 @@ class Controller(object):
|
|||||||
.format(space_id=space_guid,
|
.format(space_id=space_guid,
|
||||||
environment_id=environment_id))
|
environment_id=environment_id))
|
||||||
|
|
||||||
package = db_api.package_get(service_id, req.context)
|
package = m_cli.packages.get(service_id)
|
||||||
LOG.debug('Adding service {name}'.format(name=package.name))
|
LOG.debug('Adding service {name}'.format(name=package.name))
|
||||||
|
|
||||||
service = self._make_service(space_guid, package, plan_id)
|
service = self._make_service(space_guid, package, plan_id)
|
||||||
@@ -179,7 +181,7 @@ class Controller(object):
|
|||||||
service_id = service.service_id
|
service_id = service.service_id
|
||||||
environment_id = service.environment_id
|
environment_id = service.environment_id
|
||||||
token = req.headers['X-Auth-Token']
|
token = req.headers['X-Auth-Token']
|
||||||
m_cli = muranoclient(token)
|
m_cli = _get_muranoclient(token, req)
|
||||||
|
|
||||||
session_id = create_session(m_cli, environment_id)
|
session_id = create_session(m_cli, environment_id)
|
||||||
m_cli.services.delete(environment_id, '/' + service_id, session_id)
|
m_cli.services.delete(environment_id, '/' + service_id, session_id)
|
||||||
@@ -195,7 +197,7 @@ class Controller(object):
|
|||||||
service_id = db_service.service_id
|
service_id = db_service.service_id
|
||||||
environment_id = db_service.environment_id
|
environment_id = db_service.environment_id
|
||||||
token = req.headers['X-Auth-Token']
|
token = req.headers['X-Auth-Token']
|
||||||
m_cli = muranoclient(token)
|
m_cli = _get_muranoclient(token, req)
|
||||||
|
|
||||||
session_id = create_session(m_cli, environment_id)
|
session_id = create_session(m_cli, environment_id)
|
||||||
env = m_cli.environments.get(environment_id, session_id)
|
env = m_cli.environments.get(environment_id, session_id)
|
||||||
@@ -232,7 +234,7 @@ class Controller(object):
|
|||||||
return resp
|
return resp
|
||||||
env_id = service.environment_id
|
env_id = service.environment_id
|
||||||
token = req.headers["X-Auth-Token"]
|
token = req.headers["X-Auth-Token"]
|
||||||
m_cli = muranoclient(token)
|
m_cli = _get_muranoclient(token, req)
|
||||||
|
|
||||||
# NOTE(starodubcevna): we can track only environment status. it's
|
# NOTE(starodubcevna): we can track only environment status. it's
|
||||||
# murano API limitation.
|
# murano API limitation.
|
||||||
@@ -253,17 +255,37 @@ class Controller(object):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def muranoclient(token_id):
|
def _get_muranoclient(token_id, req):
|
||||||
# TODO(starodubcevna): I guess it can be done better.
|
|
||||||
endpoint = "http://{murano_host}:{murano_port}".format(
|
|
||||||
murano_host=CONF.bind_host, murano_port=CONF.bind_port)
|
|
||||||
insecure = False
|
|
||||||
|
|
||||||
LOG.debug('murano client created. Murano::Client <Url: {endpoint}'.format(
|
artifacts_client = None
|
||||||
endpoint=endpoint))
|
if CONF.engine.packages_service in ['glance', 'glare']:
|
||||||
|
artifacts_client = _get_glareclient(token_id, req)
|
||||||
|
|
||||||
return client.Client(1, endpoint=endpoint, token=token_id,
|
murano_url = CONF.murano.url or req.endpoints.get('murano')
|
||||||
insecure=insecure)
|
if not murano_url:
|
||||||
|
LOG.error('No murano url is specified and no "application-catalog" '
|
||||||
|
'service is registered in keystone.')
|
||||||
|
|
||||||
|
return muranoclient.Client(1, murano_url, token=token_id,
|
||||||
|
artifacts_client=artifacts_client)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_glareclient(token_id, req):
|
||||||
|
glare_settings = CONF.glare
|
||||||
|
|
||||||
|
url = glare_settings.url or req.endpoints.get('glare')
|
||||||
|
if not url:
|
||||||
|
LOG.error('No glare url is specified and no "artifact" '
|
||||||
|
'service is registered in keystone.')
|
||||||
|
|
||||||
|
return glare_client.Client(
|
||||||
|
endpoint=url, token=token_id,
|
||||||
|
insecure=glare_settings.insecure,
|
||||||
|
key_file=glare_settings.key_file or None,
|
||||||
|
ca_file=glare_settings.ca_file or None,
|
||||||
|
cert_file=glare_settings.cert_file or None,
|
||||||
|
type_name='murano',
|
||||||
|
type_version=1)
|
||||||
|
|
||||||
|
|
||||||
def create_session(client, environment_id):
|
def create_session(client, environment_id):
|
||||||
|
|||||||
@@ -33,15 +33,16 @@ class TestController(base.MuranoTestCase):
|
|||||||
'X-Project-Id': 'bar-baz'}
|
'X-Project-Id': 'bar-baz'}
|
||||||
|
|
||||||
@mock.patch('murano.common.policy.check_is_admin')
|
@mock.patch('murano.common.policy.check_is_admin')
|
||||||
@mock.patch('murano.db.catalog.api.package_search')
|
@mock.patch('murano.api.v1.cloudfoundry.cfapi._get_muranoclient')
|
||||||
def test_list(self, mock_db_search, mock_policy):
|
def test_list(self, mock_client, mock_policy):
|
||||||
|
|
||||||
pkg0 = mock.MagicMock()
|
pkg0 = mock.MagicMock()
|
||||||
pkg0.id = 'xxx'
|
pkg0.id = 'xxx'
|
||||||
pkg0.name = 'foo'
|
pkg0.name = 'foo'
|
||||||
pkg0.description = 'stub pkg'
|
pkg0.description = 'stub pkg'
|
||||||
|
|
||||||
mock_db_search.return_value = [pkg0]
|
mock_client.return_value.packages.filter =\
|
||||||
|
mock.MagicMock(return_value=[pkg0])
|
||||||
|
|
||||||
answer = {'services': [{'bindable': True,
|
answer = {'services': [{'bindable': True,
|
||||||
'description': pkg0.description,
|
'description': pkg0.description,
|
||||||
@@ -59,14 +60,13 @@ class TestController(base.MuranoTestCase):
|
|||||||
self.assertEqual(answer, resp)
|
self.assertEqual(answer, resp)
|
||||||
|
|
||||||
@mock.patch('murano.common.policy.check_is_admin')
|
@mock.patch('murano.common.policy.check_is_admin')
|
||||||
@mock.patch('murano.db.catalog.api.package_get')
|
@mock.patch('murano.api.v1.cloudfoundry.cfapi._get_muranoclient')
|
||||||
@mock.patch('murano.api.v1.cloudfoundry.cfapi.muranoclient')
|
|
||||||
@mock.patch('murano.db.services.cf_connections.set_instance_for_service')
|
@mock.patch('murano.db.services.cf_connections.set_instance_for_service')
|
||||||
@mock.patch('murano.db.services.cf_connections.get_environment_for_space')
|
@mock.patch('murano.db.services.cf_connections.get_environment_for_space')
|
||||||
@mock.patch('murano.db.services.cf_connections.get_tenant_for_org')
|
@mock.patch('murano.db.services.cf_connections.get_tenant_for_org')
|
||||||
def test_provision_from_scratch(self, mock_get_tenant,
|
def test_provision_from_scratch(self, mock_get_tenant,
|
||||||
mock_get_environment, mock_is, mock_client,
|
mock_get_environment, mock_is, mock_client,
|
||||||
mock_package, mock_policy):
|
mock_policy):
|
||||||
|
|
||||||
body = {"space_guid": "s1-p1",
|
body = {"space_guid": "s1-p1",
|
||||||
"organization_guid": "o1-r1",
|
"organization_guid": "o1-r1",
|
||||||
@@ -78,7 +78,6 @@ class TestController(base.MuranoTestCase):
|
|||||||
|
|
||||||
mock_get_environment.return_value = '555-555'
|
mock_get_environment.return_value = '555-555'
|
||||||
mock_client.return_value = mock.MagicMock()
|
mock_client.return_value = mock.MagicMock()
|
||||||
mock_package.return_value = mock.MagicMock()
|
|
||||||
|
|
||||||
resp = self.controller.provision(self.request, {}, '111-111')
|
resp = self.controller.provision(self.request, {}, '111-111')
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ class TestController(base.MuranoTestCase):
|
|||||||
|
|
||||||
@mock.patch('murano.common.policy.check_is_admin')
|
@mock.patch('murano.common.policy.check_is_admin')
|
||||||
@mock.patch('murano.db.catalog.api.package_get')
|
@mock.patch('murano.db.catalog.api.package_get')
|
||||||
@mock.patch('murano.api.v1.cloudfoundry.cfapi.muranoclient')
|
@mock.patch('murano.api.v1.cloudfoundry.cfapi._get_muranoclient')
|
||||||
@mock.patch('murano.db.services.cf_connections.set_instance_for_service')
|
@mock.patch('murano.db.services.cf_connections.set_instance_for_service')
|
||||||
@mock.patch('murano.db.services.cf_connections.set_environment_for_space')
|
@mock.patch('murano.db.services.cf_connections.set_environment_for_space')
|
||||||
@mock.patch('murano.db.services.cf_connections.set_tenant_for_org')
|
@mock.patch('murano.db.services.cf_connections.set_tenant_for_org')
|
||||||
@@ -113,7 +112,7 @@ class TestController(base.MuranoTestCase):
|
|||||||
|
|
||||||
self.assertIsInstance(resp, response.Response)
|
self.assertIsInstance(resp, response.Response)
|
||||||
|
|
||||||
@mock.patch('murano.api.v1.cloudfoundry.cfapi.muranoclient')
|
@mock.patch('murano.api.v1.cloudfoundry.cfapi._get_muranoclient')
|
||||||
@mock.patch('murano.db.services.cf_connections.get_service_for_instance')
|
@mock.patch('murano.db.services.cf_connections.get_service_for_instance')
|
||||||
def test_deprovision(self, mock_get_si, mock_client):
|
def test_deprovision(self, mock_get_si, mock_client):
|
||||||
service = mock.MagicMock()
|
service = mock.MagicMock()
|
||||||
@@ -126,7 +125,7 @@ class TestController(base.MuranoTestCase):
|
|||||||
|
|
||||||
self.assertIsInstance(resp, response.Response)
|
self.assertIsInstance(resp, response.Response)
|
||||||
|
|
||||||
@mock.patch('murano.api.v1.cloudfoundry.cfapi.muranoclient')
|
@mock.patch('murano.api.v1.cloudfoundry.cfapi._get_muranoclient')
|
||||||
@mock.patch('murano.db.services.cf_connections.get_service_for_instance')
|
@mock.patch('murano.db.services.cf_connections.get_service_for_instance')
|
||||||
def test_bind(self, mock_get_si, mock_client):
|
def test_bind(self, mock_get_si, mock_client):
|
||||||
service = mock.MagicMock()
|
service = mock.MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user