diff --git a/muranodashboard/environments/forms.py b/muranodashboard/environments/forms.py index a88fa39eb..f823d1d57 100644 --- a/muranodashboard/environments/forms.py +++ b/muranodashboard/environments/forms.py @@ -13,16 +13,57 @@ # under the License. import logging +import json from django import forms from django.utils.translation import ugettext_lazy as _ - -from muranodashboard.environments.services import get_service_choices - +from .services import get_service_choices +from .services.fields import get_murano_images log = logging.getLogger(__name__) +def filter_service_by_image_type(service, request): + def find_image_field(): + for form_cls in service.forms: + for field in form_cls.fields_template: + if field.get('type') == 'image': + return field + return None + + filtered = False + image_field = find_image_field() + if not image_field: + message = "Please provide Image field description in UI definition" + return filtered, message + specified_image_type = image_field.get('imageType') + if not specified_image_type: + message = "Please provide 'imageType' parameter in Image field " \ + "description in UI definition" + return filtered, message + + registered_murano_images = [] + available_images = get_murano_images(request) + for image in available_images: + registered_murano_images.append(image.murano_property.get('type')) + + for type in registered_murano_images: + if specified_image_type in type: + filtered = True + message = '' + else: + message = 'Murano image type "{0}" is not registered'.format( + specified_image_type) + return filtered, message + + def ChoiceServiceFormFactory(request): + filtered, not_filtered = get_service_choices( + request, filter_service_by_image_type) + class _Class(forms.Form): - service = forms.ChoiceField(label=_('Service Type'), - choices=get_service_choices(request)) + service = forms.ChoiceField( + label=_('Service Type'), + choices=filtered or [("", _("No services available"))]) + + description = forms.CharField(widget=forms.HiddenInput, + initial=json.dumps(not_filtered)) return _Class diff --git a/muranodashboard/environments/services/__init__.py b/muranodashboard/environments/services/__init__.py index 1e9215bf5..8490d418b 100644 --- a/muranodashboard/environments/services/__init__.py +++ b/muranodashboard/environments/services/__init__.py @@ -164,10 +164,16 @@ def get_service_type(wizard): return cleaned_data.get('service') -def get_service_choices(request): - return [(srv_type, service.name) for srv_type, service, forms in - iterate_over_services(request)] - +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): + has_filtered, message = filter_func(service, request) + if has_filtered: + filtered.append((srv_type, service.name)) + else: + not_filtered.append((service.name, message)) + return filtered, not_filtered get_forms = make_forms_getter() diff --git a/muranodashboard/environments/services/fields.py b/muranodashboard/environments/services/fields.py index 1d768470e..7c0d4b9d0 100644 --- a/muranodashboard/environments/services/fields.py +++ b/muranodashboard/environments/services/fields.py @@ -101,6 +101,30 @@ def wrap_regex_validator(validator, message): return _validator +def get_murano_images(request): + images = [] + try: + # public filter removed + images, _more = glance.image_list_detailed(request) + except: + log.error("Error to request image list from glance ") + exceptions.handle(request, _("Unable to retrieve public images.")) + murano_images = [] + for image in images: + murano_property = image.properties.get('murano_image_info') + if murano_property: + try: + murano_metadata = json.loads(murano_property) + except ValueError: + log.warning("JSON in image metadata is not valid. " + "Check it in glance.") + messages.error(request, _("Invalid murano image metadata")) + else: + image.murano_property = murano_metadata + murano_images.append(image) + return murano_images + + class CustomPropertiesField(forms.Field): def __init__(self, form=None, key=None, *args, **kwargs): validators = [] @@ -465,40 +489,23 @@ class ImageChoiceField(ChoiceField): @with_request def update(self, request, **kwargs): - try: - # public filter removed - images, _more = glance.image_list_detailed(request) - except: - log.error("Error to request image list from glance ") - images = [] - exceptions.handle(request, _("Unable to retrieve public images.")) - image_mapping, image_choices = {}, [] - for image in images: - murano_property = image.properties.get('murano_image_info') - if murano_property: - try: - murano_json = json.loads(murano_property) - except ValueError: - log.warning("JSON in image metadata is not valid. " - "Check it in glance.") - messages.error(request, _("Invalid murano image metadata")) - else: - title = murano_json.get('title', image.name) - murano_json['name'] = image.name + murano_images = get_murano_images(request) + for image in murano_images: + murano_data = image.murano_property + title = murano_data.get('title', image.name) + murano_data['name'] = image.name + if self.image_type is not None: + itype = murano_data.get('type') - if self.image_type is not None: - itype = murano_json.get('type') + if not self.image_type and itype is None: + continue - if not self.image_type and itype is None: - continue - - prefix = '{type}.'.format(type=self.image_type) - if (not itype.startswith(prefix) and - not self.image_type == itype): - continue - - image_mapping[smart_text(title)] = json.dumps(murano_json) + prefix = '{type}.'.format(type=self.image_type) + if (not itype.startswith(prefix) and + not self.image_type == itype): + continue + image_mapping[smart_text(title)] = json.dumps(murano_data) for name in sorted(image_mapping.keys()): image_choices.append((image_mapping[name], name)) diff --git a/muranodashboard/environments/views.py b/muranodashboard/environments/views.py index 2af527163..f7ef75649 100644 --- a/muranodashboard/environments/views.py +++ b/muranodashboard/environments/views.py @@ -15,6 +15,7 @@ import logging import re import copy +import json from django.core.urlresolvers import reverse, reverse_lazy from django.utils.translation import ugettext_lazy as _ @@ -137,10 +138,6 @@ class Wizard(ModalFormMixin, LazyWizard): def get_context_data(self, form, **kwargs): context = super(Wizard, self).get_context_data(form=form, **kwargs) - context.update({ - 'service_descriptions': get_service_descriptions(self.request), - 'environment_id': self.kwargs.get('environment_id') - }) if self.steps.index > 0: data = self.get_cleaned_data_for_step('service_choice') service_type = data['service'] @@ -148,7 +145,28 @@ class Wizard(ModalFormMixin, LazyWizard): self.request, service_type, self.steps.index - 1) service_name = get_service_name(self.request, service_type) context.update({'type': service_type, - 'service_name': service_name}) + 'service_name': service_name, + 'environment_id': self.kwargs.get('environment_id') + }) + else: + extended_description = form.fields['description'].initial or '' + if extended_description: + data = json.loads(extended_description) + unavailable_services, reasons = zip(*data) + if unavailable_services: + services_msg = ', '.join(unavailable_services) + reasons_msg = '\n'.join(set(reasons)) + extended_description = 'Services {0} are not available. ' \ + 'Reasons: {1}'.format(services_msg, + reasons_msg) + else: + extended_description = '' + + context.update({ + 'service_descriptions': get_service_descriptions(self.request), + 'extended_description': extended_description, + 'environment_id': self.kwargs.get('environment_id') + }) return context diff --git a/muranodashboard/templates/services/_wizard_create.html b/muranodashboard/templates/services/_wizard_create.html index 80eb9740d..2209d46d3 100644 --- a/muranodashboard/templates/services/_wizard_create.html +++ b/muranodashboard/templates/services/_wizard_create.html @@ -1,3 +1,7 @@ + + {% extends "common/_modal_form.html" %} {% load i18n humanize %} {% load url from future %} {# fix for django 1.4.9 on CentOS #} @@ -19,6 +23,7 @@ {% include "common/_form_fields.html" %} {% endif %} +

{% blocktrans %} {{ extended_description }} {% endblocktrans %}

{% if wizard.steps.index > 0 %} @@ -63,6 +68,8 @@ if ( selected ) { $('p.switchable:not(#'+selected+')').css('display', 'none'); $('p.switchable#'+selected).css('display', 'block'); + } else { + $('.modal-body .right').css('display', 'none'); } }); $('#id_service_choice-service').change();