No need to restart Web-server now to see changes in dynamic UI.

Workflow is simpler now: edit form definition YAML-file, save it,
reload the form it affects. Voila!

Implements: feature MRN-1147
Cherry-picked from dc78dc3b68

Change-Id: I72d68c17b829f9252560ecd01335656ffba0b262
This commit is contained in:
Timur Sufiev 2013-10-11 14:53:09 +04:00
parent 98f506d0f4
commit d9ee18a6d6
4 changed files with 82 additions and 24 deletions

View File

@ -20,7 +20,6 @@ from horizon import messages, exceptions
from openstack_dashboard.api import glance
import json
from muranodashboard.panel.services import iterate_over_service_forms
from muranodashboard.panel.services import get_service_choices
log = logging.getLogger(__name__)
@ -31,10 +30,6 @@ class WizardFormServiceType(forms.Form):
choices=get_service_choices())
FORMS = [('service_choice', WizardFormServiceType)]
FORMS.extend(iterate_over_service_forms())
class MarkImageForm(SelfHandlingForm):
_metadata = {
'windows.2012': ' Windows Server 2012',

View File

@ -21,6 +21,7 @@ from ordereddict import OrderedDict
import yaml
from yaml.scanner import ScannerError
from django.utils.translation import ugettext_lazy as _
import copy
log = logging.getLogger(__name__)
_all_services = OrderedDict()
@ -65,12 +66,20 @@ def import_all_services():
directory = getattr(settings, 'MURANO_SERVICES_DESC_PATH', None)
if directory is None:
directory = os.path.join(os.path.dirname(__file__), '../../services/')
log.debug("Importing service definitions from '{0}'".format(directory))
file_list = [f for f in os.listdir(directory) if f.endswith('.yaml')]
for filename in os.listdir(directory):
if not filename.endswith('.yaml'):
continue
log.debug("Removing non-existing service definitions from cache")
# TODO: this has O(n^2) complexity, should fix it if there are many defs
for filename in _all_services.keys():
try:
file_list.index(filename)
except ValueError:
del _all_services[filename]
log.info("Removed service '{0}' from cache".format(filename))
log.debug("Updating service definitions cache from '{0}'".format(
directory))
for filename in file_list:
service_file = os.path.join(directory, filename)
modified_on = os.path.getmtime(service_file)
@ -100,10 +109,14 @@ def iterate_over_services():
yield service.type, service, service.forms
def iterate_over_service_forms():
for srv_type, service, forms in iterate_over_services():
for step, form in enumerate(forms):
yield '{0}-{1}'.format(srv_type, step), form
def make_forms_getter(initial_forms=[]):
def _get_forms():
_forms = copy.copy(initial_forms)
for srv_type, service, forms in iterate_over_services():
for step, form in enumerate(forms):
_forms.append(('{0}-{1}'.format(srv_type, step), form))
return _forms
return _get_forms
def service_type_from_id(service_id):
@ -150,6 +163,9 @@ def get_service_choices():
iterate_over_services()]
get_forms = make_forms_getter()
def get_service_checkers():
import_all_services()
@ -159,7 +175,7 @@ def get_service_checkers():
return compare
return [(srv_id, make_comparator(srv_id)) for srv_id, form
in iterate_over_service_forms()]
in get_forms()]
def get_service_descriptions():

View File

@ -21,8 +21,9 @@ from views import DetailServiceView
from views import DeploymentsView
from views import MarkedImagesView, MarkImageView
from views import Wizard, EditEnvironmentView
from forms import FORMS
from muranodashboard.panel.services import get_service_checkers
from forms import WizardFormServiceType
from services import get_service_checkers
from services import make_forms_getter
from openstack_dashboard.dashboards.project.instances.views import DetailView
VIEW_MOD = 'openstack_dashboard.dashboards.project.murano.views'
@ -33,8 +34,9 @@ urlpatterns = patterns(
url(r'^environments$', IndexView.as_view(), name='index'),
url(r'^create/$',
Wizard.as_view(FORMS,
condition_dict=dict(get_service_checkers())),
Wizard.as_view(make_forms_getter(
initial_forms=[('service_choice', WizardFormServiceType)]),
condition_dict=get_service_checkers),
name='create'),
url(r'^create_environment$', CreateEnvironmentView.as_view(),

View File

@ -15,14 +15,13 @@
import logging
import re
import json
import copy
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text
from django.contrib.formtools.wizard.views import SessionWizardView
from django.http import HttpResponseRedirect
from openstack_dashboard.api import glance
from horizon import exceptions
@ -41,16 +40,62 @@ from workflows import CreateEnvironment, UpdateEnvironment
from tabs import ServicesTabs, DeploymentTabs
from forms import MarkImageForm
from muranodashboard.panel import api
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.panel.services import get_service_descriptions, \
get_service_name, get_service_field_descriptions
LOG = logging.getLogger(__name__)
class Wizard(ModalFormMixin, SessionWizardView):
class LazyWizard(SessionWizardView):
"""The class which defers evaluation of form_list and condition_dict
until view method is called. So, each time we load a page with a dynamic
UI form, it will have markup/logic from the newest YAML-file definition.
"""
@classonlymethod
def as_view(cls, initforms, *initargs, **initkwargs):
"""
Main entry point for a request-response process.
"""
# sanitize keyword arguments
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(u"You tried to pass in the %s method name as a"
u" keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError(u"%s() received an invalid keyword %r" % (
cls.__name__, key))
def view(request, *args, **kwargs):
forms = initforms
if hasattr(initforms, '__call__'):
forms = initforms()
condition_dict = initkwargs.get('condition_dict', False)
_kwargs = copy.copy(initkwargs)
if condition_dict and hasattr(condition_dict, '__call__'):
_kwargs.update({'condition_dict': dict(condition_dict())})
_kwargs = cls.get_initkwargs(forms, *initargs, **_kwargs)
self = cls(**_kwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
class Wizard(ModalFormMixin, LazyWizard):
template_name = 'services/wizard_create.html'
def done(self, form_list, **kwargs):