'GetPackageUI' API can now be called even if Glare is used

Since Glare support was introduced the 'catalog/packages' part of
Murano API (/v1/catalog/packages) became obsolete and was intended to
be used for "legacy" (i.e. non-glare-based) package storage. The
murano client was supposed to directly call glare to retrieve the
packages.

However, the "GetPackageUI" call (GET
/v1/catalog/packages/%pkg_id%/ui) is different: not all the packages
bundle the UI definitions, some require Murano to generate them based
on the contents of the package. This is true for HOT-based packages
and others, plugin-based ones. In future this will be true for 100% of
the packages when the dynamic ui and object model generation is added.

Because of this that API should be callable even if Glare is
configured as a package storage backend. It should fetch the artifact
from glare, unpack it and use whatever plugin-specific logic required
to generate the UI definitions for this particular package.

This patch introduces appropriate change while maintaining the
backwards compatibility: in the legacy mode (i.e. when murano's DB
acts as package storage) the UI is read directly from an appropriate
DB table without fetching the whole package.

This fixes the issue when the HOT-based packages could not be
deplpoyed properly with murano-dashboard, but the murano-client has to
be updated as well to properly call the modified API even if Glare is
enabled.

Change-Id: Id9327e4015e1c0a1553c0b1a0151a94ee4da2928
Partial-bug: #1565805
This commit is contained in:
Alexander Tivelkov 2016-04-05 19:04:27 +03:00
parent 0b3778af7c
commit 2858689767
4 changed files with 62 additions and 6 deletions

View File

@ -14,6 +14,7 @@
from oslo_config import cfg
from oslo_middleware import request_id as oslo_request_id
from oslo_serialization import jsonutils
from murano.common.i18n import _
from murano.common import wsgi
@ -50,6 +51,9 @@ class ContextMiddleware(wsgi.Middleware):
'request_id': req.environ.get(oslo_request_id.ENV_REQUEST_ID),
'roles': roles
}
sc_header = req.headers.get('X-Service-Catalog')
if sc_header:
kwargs['service_catalog'] = jsonutils.loads(sc_header)
req.context = murano.context.RequestContext(**kwargs)
@classmethod

View File

@ -18,6 +18,8 @@ import os
import tempfile
import jsonschema
from keystoneclient import exceptions as keystone_ex
from keystoneclient import service_catalog
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
@ -34,6 +36,7 @@ from murano.db.catalog import api as db_api
from murano.common.i18n import _, _LW
from murano.packages import exceptions as pkg_exc
from murano.packages import load_utils
from muranoclient.glance import client as glare_client
LOG = logging.getLogger(__name__)
@ -266,11 +269,21 @@ class Controller(object):
os.remove(tempf.name)
def get_ui(self, req, package_id):
target = {'package_id': package_id}
policy.check("get_package", req.context, target)
if CONF.engine.packages_service == 'murano':
target = {'package_id': package_id}
policy.check("get_package", req.context, target)
package = db_api.package_get(package_id, req.context)
return package.ui_definition
package = db_api.package_get(package_id, req.context)
return package.ui_definition
else:
g_client = self._get_glare_client(req)
blob_data = g_client.artifacts.download_blob(package_id, 'archive')
with tempfile.NamedTemporaryFile() as tempf:
for chunk in blob_data:
tempf.write(chunk)
with load_utils.load_from_file(tempf.name, target_dir=None,
drop_dir=True) as pkg:
return pkg.ui
def get_logo(self, req, package_id):
target = {'package_id': package_id}
@ -392,6 +405,38 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=msg)
db_api.category_delete(category_id)
def _get_glare_client(self, request):
glare_settings = CONF.glare
token = request.context.auth_token
url = glare_settings.url
if not url:
self._get_glare_url(request)
client = glare_client.Client(
endpoint=url, token=token, 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)
return client
def _get_glare_url(self, request):
sc = request.context.service_catalog
token = request.context.auth_token
try:
return service_catalog.ServiceCatalogV2(
{'serviceCatalog': sc}).url_for(
service_type='artifact',
endpoint_type=CONF.glare.endpoint_type,
region_name=CONF.home_region)
except keystone_ex.EndpointNotFound:
return service_catalog.ServiceCatalogV3(
token,
{'catalog': sc}).url_for(
service_type='artifact',
endpoint_type=CONF.glare.endpoint_type,
region_name=CONF.home_region)
def create_resource():
specific_content_types = {

View File

@ -25,11 +25,12 @@ class RequestContext(context.RequestContext):
"""
def __init__(self, session=None,
roles=None, is_admin=None,
roles=None, is_admin=None, service_catalog=None,
**kwargs):
super(RequestContext, self).__init__(**kwargs)
self.session = session
self.roles = roles or []
self.service_catalog = service_catalog
self.is_admin = is_admin
if self.is_admin is None:
self.is_admin = policy.check_is_admin(self)

View File

@ -0,0 +1,6 @@
---
fixes:
- Fixed a bug when the UI dialog was not displayed in Murano Dashboard for
applications which don't have UI definitions bundled in the package but
generate them based on the package contents instead. This usually affected
HOT-based packages and other non-muranopl-based applications.