Cherry-pick the following commits from master:

* Made  improvements for rpmbuild
  I1dd7a54f7ade5414ad07cb8e12d0b018ecbc63c2
* Return status code instead of detailes
  Id0fe5dcae7ae19dee455a7ae8928e4a0d55fca26
* Add ability to delete file from service
  I6490ac2a391149a8660d5800b62ce8196e47bf00
* Add author field to the Compose Service form
  Increment service version after modification
  Forbid to edit version
  Closes bugs: #1262237, #1262239, #1262242
  I5061704c7a3ca96c26d79edfb9f551df3e2f80e2
* Update instance link formation due to changes in Havana
  Fixes-bug: #1262713
  I56e174f35ef4a60cffe31b0e619b53845a701ad6
* Add link with stack details in service details
  Ic3e34c9d341309ffd005a5479b2a6ef12b3bfe05
  Implements: blueprint add-stack-link
* Rename dynamic_ui package and normalize it.
  * Move muranodashboard.environments.services package to
    muranodashboard.dynamic_ui.
  * Move all code from dynamic_ui/__init__.py to dynamic_ui/services.py
    thus having normal empty __init__.py for dynamic_ui package (as in
      other packages).
  I395ee621578cb417314fe4960d74108deb848023
* Minor refactoring of dynamic_ui package.
  Remove one inner import in dynamic_ui.services and rewrite a bit
  iterate_over_services() function.
  If14022435a5ef269a448d5f568fe0f33421c9f23
* Do not log exception, if it is Http302 (redirect).
  I3488fc8523ec2e4628a26006c0211d2d468f189a
* Show more sensible error messages during Service Creation.
  If Metadata Repository is not available, show more concise error
  messages.
  Also refactor wrapper for handling Metadata Repository exceptions,
  thus allowing to throw-away some boilerplate code.
  I6acd94bf2ca397941f45bc4c8d9e9fe74678b5ee
  Closes-bug: #1263463

Change-Id: Ia814eccf6841f7dcc153cf0c3c7c793f0f358023
This commit is contained in:
Igor Yozhikov 2013-12-12 13:52:08 +04:00 committed by Timur Sufiev
parent 1206c4119a
commit c70a008456
23 changed files with 321 additions and 148 deletions

View File

@ -1,6 +1,5 @@
recursive-include muranodashboard/static *
recursive-include muranodashboard/templates *
include muranodashboard/services/*.yaml
include tools/pip-requires
include run_tests.sh
include ChangeLog
@ -9,6 +8,6 @@ include MANIFEST.in
include AUTHORS
include LICENSE
include ChangeLog
include babel.cfg
include tox.ini
recursive-include build_addons/rpm *.sh
global-exclude *.pyc

View File

@ -0,0 +1,67 @@
Name: murano-dashboard
Version: 0.4
Release: 5%{?dist}
Summary: OpenStack Murano Dashboard
Group: Applications/Communications
License: Apache License, Version 2.0
URL: https://launchpad.net/murano
Source0: murano-dashboard-0.4.tar.gz
BuildArch: noarch
Requires: openstack-dashboard
Requires: python-eventlet
BuildRequires: python2-devel
BuildRequires: python-setuptools
BuildRequires: python-pbr
BuildRequires: python-d2to1
Requires: python-pbr >= 0.5.21, python-pbr < 1.0
Requires: python-anyjson >= 0.3.3
Requires: python-bunch >= 1.0.1
Requires: python-iso8601 >= 0.1.8
Requires: python-six >= 1.4.1
Requires: PyYAML >= 3.10
Requires: python-django-floppyforms >= 1.1
Requires: python-ordereddict >= 1.1
Requires: python-yaql >= 0.2
Requires: python-muranoclient >= 0.4
Requires: murano-metadataclient >= 0.4
%description
Murano Dashboard
Sytem package - murano-dashboard
Python package - murano-dashboard
%prep
%setup -q muranodashboard-%{version}
%build
%{__python} setup.py build
%install
%{__python} setup.py install -O1 --skip-build --root %{buildroot}
mkdir -p %{buildroot}/usr/bin
cp %{_builddir}/murano-dashboard-%{version}/build_addons/rpm/modify-horizon-config.sh %{buildroot}/usr/bin/
%post
/usr/bin/modify-horizon-config.sh install
if [ ! -d "/var/log/murano" ]; then
mkdir -p /var/log/murano
fi
touch /var/log/murano/murano-dashboard.log
mkdir -p /usr/share/openstack-dashboard/static/floppyforms
mkdir -p /usr/share/openstack-dashboard/static/muranodashboard
chown -R apache:root /usr/share/openstack-dashboard/static/muranodashboard
chown -R apache:root /usr/share/openstack-dashboard/static/floppyforms
chown apache:root /var/log/murano/murano-dashboard.log
su -c "python /usr/share/openstack-dashboard/manage.py collectstatic --noinput | /usr/bin/logger -t murano-dashboard-install " -s /bin/bash apache
service httpd restart
%files
%{python_sitelib}/*
/usr/bin/*
%changelog
* Thu Dec 12 2013 built by Igor Yozhikov <iyozhikov@mirantis.com>
- build number - 5

View File

@ -0,0 +1,54 @@
Name: #SYS_PKG_NAME#
Version: 0.4
Release: #RELEASE#
Summary: OpenStack Murano Dashboard
Group: Applications/Communications
License: #LICENSE#
URL: #URL#
Source0: #SOURCE0#
BuildArch: noarch
Requires: openstack-dashboard
Requires: python-eventlet
BuildRequires: python2-devel
BuildRequires: python-setuptools
BuildRequires: python-pbr
BuildRequires: python-d2to1
#REQUIRES#
%description
Murano Dashboard
#DESCRIPTION#
%prep
%setup -q muranodashboard-%{version}
%build
%{__python} setup.py build
%install
%{__python} setup.py install -O1 --skip-build --root %{buildroot}
mkdir -p %{buildroot}/usr/bin
cp %{_builddir}/murano-dashboard-%{version}/build_addons/rpm/modify-horizon-config.sh %{buildroot}/usr/bin/
%post
/usr/bin/modify-horizon-config.sh install
if [ ! -d "/var/log/murano" ]; then
mkdir -p /var/log/murano
fi
touch /var/log/murano/murano-dashboard.log
mkdir -p /usr/share/openstack-dashboard/static/floppyforms
mkdir -p /usr/share/openstack-dashboard/static/muranodashboard
chown -R apache:root /usr/share/openstack-dashboard/static/muranodashboard
chown -R apache:root /usr/share/openstack-dashboard/static/floppyforms
chown apache:root /var/log/murano/murano-dashboard.log
su -c "python /usr/share/openstack-dashboard/manage.py collectstatic --noinput | /usr/bin/logger -t murano-dashboard-install " -s /bin/bash apache
service httpd restart
%files
%{python_sitelib}/*
/usr/bin/*
%changelog
#CHANGELOG#

View File

@ -0,0 +1,13 @@
# Copyright (c) 2013 Mirantis, 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.

View File

@ -14,13 +14,15 @@
import re
import logging
import types
from django import forms
from django.core.validators import RegexValidator
from django.utils.translation import ugettext_lazy as _
import muranodashboard.environments.services.fields as fields
import muranodashboard.environments.services.helpers as helpers
import muranodashboard.dynamic_ui.fields as fields
import muranodashboard.dynamic_ui.helpers as helpers
import yaql
import types
log = logging.getLogger(__name__)

View File

@ -19,7 +19,8 @@ import tarfile
import logging
import shutil
import hashlib
from ..consts import CHUNK_SIZE, CACHE_DIR, ARCHIVE_PKG_PATH
from muranodashboard.environments.consts import CHUNK_SIZE, CACHE_DIR, \
ARCHIVE_PKG_PATH
log = logging.getLogger(__name__)
@ -27,6 +28,11 @@ log = logging.getLogger(__name__)
from horizon.exceptions import ServiceCatalogException
from openstack_dashboard.api.base import url_for
from metadataclient.v1.client import Client
from metadataclient.common.exceptions import CommunicationError, Unauthorized
from metadataclient.common.exceptions import HTTPInternalServerError
from horizon import exceptions
from django.utils.translation import ugettext_lazy as _
from contextlib import contextmanager
if not os.path.exists(CACHE_DIR):
@ -106,6 +112,26 @@ def unpack_ui_package(archive_path):
return dst_dir
@contextmanager
def metadata_exceptions(request):
"""Handles all metadata-repository specific exceptions."""
try:
yield
except CommunicationError:
msg = _('Unable to communicate to Murano Metadata Repository. Add '
'MURANO_METADATA_URL to local_settings')
log.exception(msg)
exceptions.handle(request, msg)
except Unauthorized:
msg = _('Configure Keystone in Murano Repository Service')
log.exception(msg)
exceptions.handle(request, msg)
except HTTPInternalServerError:
msg = _('There is a problem with Murano Repository Service')
log.exception(msg)
exceptions.handle(request, msg)
def get_ui_metadata(request):
"""Returns directory with unpacked definitions provided by Metadata
Repository at `endpoint' URL or, if it was not found or some error has
@ -116,9 +142,17 @@ def get_ui_metadata(request):
if hash:
metadata_dir = os.path.join(CACHE_DIR, hash)
#ToDO: Do we need to catch exception here?
response, body_iter = metadataclient(request).metadata_client.get_ui_data(
hash)
data = None
with metadata_exceptions(request):
data = metadataclient(request).metadata_client.get_ui_data(hash)
# mimic normal return value in case metadata repository exception has just
# been handled.
# TODO: it would be better to use redirect here
if data is None:
return None, False
response, body_iter = data
code = response.status
if code == 200:
with tempfile.NamedTemporaryFile(delete=False) as out:
@ -135,9 +169,14 @@ def get_ui_metadata(request):
log.info("Metadata package hash-sum hasn't changed, doing nothing")
return metadata_dir, False
else:
msq = 'Unexpected response received: {0}'.format(code)
msg = 'Unexpected response received: {0}'.format(code)
if hash:
log.error('Using existing version of metadata '
'which may be outdated due to: {0}'.format(msq))
'which may be outdated due to: {0}'.format(msg))
return metadata_dir, False
raise RuntimeError(msq)
else:
log.error('Unable to load any metadata due to: {0}'.format(msg))
exceptions.handle(
request,
_('There is a problem with Murano Repository Service'))
return None, False

View File

@ -12,10 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import re
import time
import logging
from muranodashboard.dynamic_ui import metadata
from muranodashboard.dynamic_ui.helpers import decamelize
try:
from collections import OrderedDict
except ImportError: # python2.6
@ -24,8 +28,7 @@ import yaml
from yaml.scanner import ScannerError
from django.utils.translation import ugettext_lazy as _
import copy
from ..consts import CACHE_REFRESH_SECONDS_INTERVAL
import metadata
from muranodashboard.environments.consts import CACHE_REFRESH_SECONDS_INTERVAL
log = logging.getLogger(__name__)
_all_services = OrderedDict()
@ -35,7 +38,7 @@ _current_cache_hash = None
class Service(object):
def __init__(self, **kwargs):
import muranodashboard.environments.services.forms as services
import muranodashboard.dynamic_ui.forms as services
for key, value in kwargs.iteritems():
if key == 'forms':
self.forms = []
@ -66,7 +69,6 @@ class Service(object):
def import_service(full_service_name, service_file):
from muranodashboard.environments.services.helpers import decamelize
try:
with open(service_file) as stream:
yaml_desc = yaml.load(stream)
@ -109,7 +111,10 @@ def import_all_services(request):
if time.time() - _last_check_time > CACHE_REFRESH_SECONDS_INTERVAL:
_last_check_time = time.time()
directory, modified = metadata.get_ui_metadata(request)
if modified or not are_caches_in_sync():
# check directory here in case metadata service is not available
# and None is returned as directory value.
# TODO: it is better to use redirect for that purpose (if possible)
if modified or (directory and not are_caches_in_sync()):
_all_services = {}
for full_service_name in os.listdir(directory):
final_dir = os.path.join(directory, full_service_name)
@ -124,14 +129,14 @@ def import_all_services(request):
def iterate_over_services(request):
import_all_services(request)
for service in sorted(_all_services.values(), key=lambda v: v.name):
yield service.type, service, service.forms
yield service.type, service
def make_forms_getter(initial_forms=lambda request: copy.copy([])):
def _get_forms(request):
_forms = initial_forms(request)
for srv_type, service, forms in iterate_over_services(request):
for step, form in enumerate(forms):
for srv_type, service in iterate_over_services(request):
for step, form in enumerate(service.forms):
_forms.append(('{0}-{1}'.format(srv_type, step), form))
return _forms
return _get_forms
@ -147,7 +152,7 @@ def service_type_from_id(service_id):
def with_service(request, service_id, getter, default):
service_type = service_type_from_id(service_id)
for srv_type, service, forms in iterate_over_services(request):
for srv_type, service in iterate_over_services(request):
if srv_type == service_type:
return getter(service)
return default
@ -178,7 +183,7 @@ def get_service_type(wizard):
def get_service_choices(request, filter_func=None):
filter_func = filter_func or (lambda srv: True, None)
filtered, not_filtered = [], []
for srv_type, service, forms in iterate_over_services(request):
for srv_type, service in iterate_over_services(request):
has_filtered, message = filter_func(service, request)
if has_filtered:
filtered.append((srv_type, service.name))
@ -201,7 +206,7 @@ def get_service_checkers(request):
def get_service_descriptions(request):
descriptions = []
for srv_type, service, forms in iterate_over_services(request):
for srv_type, service in iterate_over_services(request):
description = getattr(service, 'description', _("<b>Default service \
description</b>. If you want to see here something meaningful, please \
provide `description' field in service markup."))

View File

@ -18,7 +18,7 @@ from django.conf import settings
from horizon.exceptions import ServiceCatalogException
from openstack_dashboard.api.base import url_for
from muranoclient.v1.client import Client
from muranodashboard.environments.services import get_service_name
from muranodashboard.dynamic_ui.services import get_service_name
from muranoclient.common.exceptions import HTTPForbidden, HTTPNotFound
from consts import STATUS_ID_READY, STATUS_ID_NEW
from .network import get_network_params

View File

@ -16,8 +16,8 @@ import logging
import json
from django import forms
from django.utils.translation import ugettext_lazy as _
from .services import get_service_choices
from .services.fields import get_murano_images
from muranodashboard.dynamic_ui.services import get_service_choices
from muranodashboard.dynamic_ui.fields import get_murano_images
log = logging.getLogger(__name__)

View File

@ -20,6 +20,7 @@ from horizon import tabs
from muranodashboard.environments.consts import LOG_LEVEL_TO_COLOR
from muranodashboard.environments.consts import LOG_LEVEL_TO_TEXT
from openstack_dashboard.api import nova as nova_api
from openstack_dashboard.api import heat as heat_api
from muranodashboard.environments import api
from muranodashboard.environments.tables import STATUS_DISPLAY_CHOICES
@ -87,13 +88,24 @@ class OverviewTab(tabs.Tab):
instances = nova_api.server_list(request)[0]
# HEAT always adds e before instance name
instance_name = 'e' + environment_id + '.' + instance_hostname
instance_name = 'e' + environment_id + '-' + instance_hostname
for instance in instances:
if instance.name == instance_name:
if instance_name in instance.name:
unit_detail['instance'] = {
'id': instance.id,
'name': instance_name
'name': instance.name
}
break
# add stack info
stack_name = 'e' + environment_id
existing_stacks = heat_api.stacks_list(request)
for stack in existing_stacks:
if stack.stack_name == stack_name:
unit_detail['stack'] = {
'id': stack.id,
'name': stack.stack_name
}
break

View File

@ -21,8 +21,8 @@ from views import DetailServiceView
from views import DeploymentsView
from views import Wizard, EditEnvironmentView
from forms import ChoiceServiceFormFactory
from services import get_service_checkers
from services import make_forms_getter
from muranodashboard.dynamic_ui.services import get_service_checkers
from muranodashboard.dynamic_ui.services import make_forms_getter
from openstack_dashboard.dashboards.project.instances.views import DetailView
VIEW_MOD = 'muranodashboard.environments.views'

View File

@ -16,12 +16,12 @@ import logging
import re
import copy
import json
from functools import update_wrapper
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.contrib.formtools.wizard.views import SessionWizardView
from django.http import HttpResponseRedirect
from horizon import exceptions
from horizon import tabs
from horizon import tables
@ -32,18 +32,16 @@ from tables import EnvironmentsTable
from tables import ServicesTable
from tables import DeploymentsTable
from tables import EnvConfigTable
from workflows import CreateEnvironment, UpdateEnvironment
from tabs import ServicesTabs, DeploymentTabs
from . import api
from muranoclient.common.exceptions import HTTPUnauthorized, \
CommunicationError, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
from functools import update_wrapper
from django.utils.decorators import classonlymethod
from services import get_service_descriptions
from services import get_service_name
from services import get_service_field_descriptions
from muranodashboard.dynamic_ui.services import get_service_descriptions
from muranodashboard.dynamic_ui.services import get_service_name
from muranodashboard.dynamic_ui.services import get_service_field_descriptions
LOG = logging.getLogger(__name__)

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from horizon.middleware import HorizonMiddleware
from horizon.exceptions import Http302
import traceback
import logging
@ -21,6 +22,7 @@ logger = logging.getLogger(__name__)
class ExceptionMiddleware(HorizonMiddleware):
def process_exception(self, request, exception):
logger.error(traceback.format_exc())
if not isinstance(exception, Http302):
logger.error(traceback.format_exc())
return super(ExceptionMiddleware, self).process_exception(
request, exception)

View File

@ -19,7 +19,7 @@ from horizon.forms import SelfHandlingForm
from horizon import exceptions
from horizon import messages
from metadataclient.common.exceptions import HTTPException
from muranodashboard.environments.services.metadata import metadataclient
from muranodashboard.dynamic_ui.metadata import metadataclient
log = logging.getLogger(__name__)
@ -38,16 +38,13 @@ class UploadServiceForm(SelfHandlingForm):
except HTTPException as e:
log.exception(e)
redirect = reverse('horizon:murano:service_catalog:index')
if e.code == 400:
msg = 'File already exists'
else:
msg = e.details
exceptions.handle(request, _('Unable to upload service: '
'{0}'.format(msg)),
exceptions.handle(request,
_('Unable to upload service. '
'Error code: {0}'.format(e.code)),
redirect=redirect)
class UploadFileKnownTypeForm(SelfHandlingForm):
class UploadFileToService(SelfHandlingForm):
file = forms.FileField(label=_('Murano Repository File'),
required=True,
error_messages=
@ -59,7 +56,7 @@ class UploadFileKnownTypeForm(SelfHandlingForm):
*args, **kwargs):
self.data_type = data_type
self.service_id = full_service_name
super(UploadFileKnownTypeForm, self).__init__(request, *args, **kwargs)
super(UploadFileToService, self).__init__(request, *args, **kwargs)
def handle(self, request, data):
filename = data['file'].name
@ -94,7 +91,7 @@ class UploadFileKnownTypeForm(SelfHandlingForm):
return file
class UploadFileForm(UploadFileKnownTypeForm):
class UploadFileForm(UploadFileToService):
supported_data_types = {
'ui': 'UI Definition (*.yaml)',
'workflows': 'Murano Conductor Workflow (*xml)',

View File

@ -21,7 +21,7 @@ from horizon import exceptions
from horizon import tables
from horizon import messages
from metadataclient.common.exceptions import HTTPException
from muranodashboard.environments.services.metadata import metadataclient
from muranodashboard.dynamic_ui.metadata import metadataclient
LOG = logging.getLogger(__name__)
@ -137,6 +137,8 @@ class ServiceCatalogTable(tables.DataTable):
service_valid = tables.Column('valid', verbose_name=_('Valid'))
service_author = tables.Column('author', verbose_name=_('Author'))
service_version = tables.Column('service_version',
verbose_name=_('Version'))
def get_object_display(self, datum):
return datum.service_display_name
@ -197,6 +199,26 @@ class DeleteFile(tables.DeleteAction):
redirect=redirect)
class DeleteFileFromService(tables.DeleteAction):
name = 'delete_file_from_service'
data_type_singular = _('File')
def delete(self, request, obj_id):
service_id = self.table.kwargs.get('full_service_name')
try:
data_type, filename = obj_id.split('##')
metadataclient(request).metadata_admin.delete_from_service(
data_type, filename, service_id)
except HTTPException as e:
LOG.exception(e)
redirect = reverse('horizon:murano:service_catalog:manage_service',
args=(service_id,))
exceptions.handle(
request,
_('Unable to remove file: {0}'.format(filename)),
redirect=redirect)
class UploadFile(tables.LinkAction):
name = 'upload_file'
verbose_name = _('Upload File')

View File

@ -13,14 +13,12 @@
# under the License.
import logging
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse, reverse_lazy
from .tables import DeleteFile, DownloadFile
from .forms import UploadFileKnownTypeForm
from .tables import DeleteFileFromService, DownloadFile
from horizon import tables, workflows, forms
from muranodashboard.environments.services.forms import UpdatableFieldsForm
from muranodashboard.environments.services.fields import TableField
from muranodashboard.environments.services.fields import Column, CheckColumn
from muranodashboard.environments.services.fields import RadioColumn
from muranodashboard.dynamic_ui.forms import UpdatableFieldsForm
from muranodashboard.dynamic_ui.fields import TableField
from muranodashboard.dynamic_ui.fields import Column, CheckColumn
from muranodashboard.dynamic_ui.fields import RadioColumn
LOG = logging.getLogger(__name__)
@ -58,11 +56,11 @@ def define_tables(table_name, step_verbose_name):
name = table_name
verbose_name = step_verbose_name
table_actions = (UploadFileDataType,
DeleteFile,
DeleteFileFromService,
)
row_actions = (DownloadFile,
DeleteFile,
DeleteFileFromService,
)
return ObjectsTable

View File

@ -13,7 +13,6 @@
# under the License.
import logging
from functools import wraps
from django.core.urlresolvers import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _
@ -26,52 +25,24 @@ from horizon.forms.views import ModalFormView
from .tables import ServiceCatalogTable, MetadataObjectsTable
from .utils import define_tables
from .utils import STEP_NAMES
from .forms import UploadServiceForm, UploadFileForm, UploadFileKnownTypeForm
from .forms import UploadServiceForm, UploadFileForm, UploadFileToService
from .workflows import ComposeService
from muranodashboard.environments.services.metadata import metadataclient
from metadataclient.common.exceptions import CommunicationError, Unauthorized
from muranodashboard.dynamic_ui.metadata import metadataclient
from muranodashboard.dynamic_ui.metadata import metadata_exceptions
from metadataclient.common.exceptions import HTTPInternalServerError, NotFound
LOG = logging.getLogger(__name__)
def with_exception_handlers(default):
def decorator(func):
@wraps(func)
def wrapper(self):
value = default
try:
value = func(self)
except CommunicationError:
LOG.exception(CommunicationError)
exceptions.handle(
self.request,
_('Unable to communicate to Murano Metadata '
'Repository. Add MURANO_METADATA_URL to local_'
'settings'))
except Unauthorized:
LOG.exception(CommunicationError)
exceptions.handle(
self.request, _('Configure Keystone in Murano '
'Repository Service'))
except HTTPInternalServerError:
LOG.exception(CommunicationError)
exceptions.handle(
self.request, _('There is a problem with Murano '
'Repository Service'))
return value
return wrapper
return decorator
class ServiceCatalogView(tables.DataTableView):
table_class = ServiceCatalogTable
template_name = 'service_catalog/index.html'
@with_exception_handlers([])
def get_data(self):
return metadataclient(self.request).metadata_admin.list_services()
services, request = [], self.request
with metadata_exceptions(request):
services = metadataclient(request).metadata_admin.list_services()
return services
class UploadServiceView(ModalFormView):
@ -85,9 +56,12 @@ class ManageFilesView(tables.DataTableView):
table_class = MetadataObjectsTable
template_name = 'service_catalog/files.html'
@with_exception_handlers([])
def get_data(self):
return metadataclient(self.request).metadata_admin.get_service_files()
files, request = [], self.request
with metadata_exceptions(request):
files = metadataclient(request).metadata_admin.get_service_files()
return files
class ComposeServiceView(WorkflowView):
@ -121,7 +95,8 @@ class ComposeServiceView(WorkflowView):
'service_display_name':
service.service_display_name,
'author': getattr(service, 'author', ''),
'version': getattr(service, 'version', 0.1),
'service_version': getattr(service,
'service_version', 0),
'description': getattr(service, 'description', ''),
'enabled': getattr(service, 'enabled', False)
})
@ -138,7 +113,7 @@ class ComposeServiceView(WorkflowView):
class UploadFileView2(ModalFormView):
template_name = 'service_catalog/upload_file2.html'
form_class = UploadFileKnownTypeForm
form_class = UploadFileToService
success_url = 'horizon:murano:service_catalog:manage_service'
def get_success_url(self):
@ -189,28 +164,12 @@ class ManageServiceView(tables.MultiTableView):
super(ManageServiceView, self).__init__(*args, **kwargs)
def _get_data(self, full_service_name):
result = []
try:
result = metadataclient(self.request).metadata_admin.\
get_service_info(full_service_name)
info, request = {}, self.request
with metadata_exceptions(request):
info = metadataclient(request).metadata_admin.get_service_info(
full_service_name)
except CommunicationError as e:
LOG.exception(e)
exceptions.handle(self.request,
_('Unable to communicate to Murano Metadata '
'Repository. Add MURANO_METADATA_URL to local_'
'settings'))
except Unauthorized as e:
LOG.exception(e)
exceptions.handle(self.request, _('Configure Keystone in Murano '
'Repository Service'))
except HTTPInternalServerError as e:
LOG.exception(e)
exceptions.handle(self.request, _('There is a problem with Murano '
'Repository Service'))
else:
return result
return result
return info
def get_context_data(self, **kwargs):
context = super(ManageServiceView,
@ -232,25 +191,13 @@ class ManageServiceView(tables.MultiTableView):
def get_file_list(self, data_type):
full_service_name = self.kwargs['full_service_name']
ui_files = []
try:
ui_files = metadataclient(self.request).metadata_admin. \
get_service_files(data_type, full_service_name)
except CommunicationError as e:
LOG.exception(e)
exceptions.handle(self.request,
_('Unable to communicate to Murano Metadata '
'Repository. Add MURANO_METADATA_URL to local_'
'settings'))
except Unauthorized as e:
LOG.exception(e)
exceptions.handle(self.request, _('Configure Keystone in Murano '
'Repository Service'))
except HTTPInternalServerError as e:
LOG.exception(e)
exceptions.handle(self.request, _('There is a problem with Murano '
'Repository Service'))
return [file for file in ui_files if file.selected]
files, request = [], self.request
with metadata_exceptions(request):
files = metadataclient(request).metadata_admin.get_service_files(
data_type, full_service_name)
return [file for file in files if file.selected]
def get_ui_data(self):
return self.get_file_list('ui')

View File

@ -21,7 +21,7 @@ from horizon import exceptions
from horizon import forms
from horizon import workflows
from muranodashboard.environments.services.metadata import metadataclient
from muranodashboard.dynamic_ui.metadata import metadataclient
log = logging.getLogger(__name__)
@ -32,18 +32,21 @@ class EditManifest(Action):
full_service_name = forms.RegexField(
r'^[a-zA-Z0-9.]+$',
label=_('Fully Qualified Service Name'), required=True)
version = forms.CharField(label=_('Version'), initial='1')
author = forms.CharField(label=_('Author'))
enabled = forms.BooleanField(label=_('Active'), initial=True,
widget=CheckboxInput)
description = forms.CharField(label=_('Description'),
widget=forms.Textarea)
service_version = forms.IntegerField(label=_('Version'), initial=0)
def __init__(self, request, context, *args, **kwargs):
super(EditManifest, self).__init__(request, context, *args, **kwargs)
# disable field with service_id for service being modified
self.fields['service_version'].widget.attrs.update(
{'disabled': True, })
if context and context.get('full_service_name'):
self.fields['full_service_name'].widget.attrs.update({
'disabled': True
'disabled': True,
})
class Meta:
@ -56,7 +59,7 @@ class EditManifestStep(workflows.Step):
action_class = EditManifest
template_name = 'service_catalog/_workflow_step.html'
contributes = ('service_display_name', 'full_service_name',
'version', 'enabled', 'description')
'author', 'service_version', 'enabled', 'description')
# Workflow doesn't handle Media inner class of widgets for us, so we need
# to inject media directly to the step

View File

@ -1,7 +1,8 @@
{% load i18n %}
<p>{% blocktrans %}<strong>Service Name:</strong> is a human-readable service name.
<p>{% blocktrans %}<strong>Service Name:</strong> is a human-readable service name
{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Fully Qualified Service Name:</strong> is an internal service name. It should be unique and can contain only alphanumeric symbols and dots.{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Version:</strong> is a service version.{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Fully Qualified Service Name:</strong> is an internal service name. It should be unique and can contain only alphanumeric symbols and dots{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Author:</strong> is a company or person name{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Active:</strong> whether this service should be visible for users or not.{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Description:</strong> add text information about service. It will appear in service creation form in the Environments panel.{% endblocktrans %}</p>
<p>{% blocktrans %}<strong>Version:</strong> is a service version. Will increment automatically{% endblocktrans %}</p>

View File

@ -13,6 +13,13 @@
{{ value.name }}
</a>
</dd><br>
{% elif key == 'stack'%}
<dt>Heat stack name</dt>
<dd>
<a href=" {% url 'horizon:project:stacks:detail' value.id %}">
{{ value.name }}
</a>
</dd><br>
{% else %}
<dt>{% blocktrans %} {{ key }} {% endblocktrans %}</dt>
<dd>{% blocktrans %} {{ value }} {% endblocktrans %}</dd>
@ -35,6 +42,13 @@
{{ value.name }}
</a>
</dd><br>
{% elif key == 'stack'%}
<dt>Heat stack name</dt>
<dd>
<a href=" {% url 'horizon:project:stacks:detail' value.id %}">
{{ value.name }}
</a>
</dd><br>
{% else %}
<dt>{% blocktrans %} {{ key }} {% endblocktrans %}</dt>
<dd>{% blocktrans %} {{ value }} {% endblocktrans %}</dd>

View File

@ -15,7 +15,7 @@
[metadata]
name = murano-dashboard
version = 0.2
version = 0.4
summary = The Murano Dashboard
description-file =
README.rst