Guided cluster creation mode for Sahara

Adding a guide for cluster creation in
data processing.  This is meant to weave
the existing panels and forms together in
a way that can be understood by all users.

Partial-Implements: blueprint data-processing-rework-ui

Change-Id: Icfd0c53e90fdb7a520a034ffcc20a3752976f54c
This commit is contained in:
Chad Roberts 2014-10-21 09:34:05 -04:00
parent 4dec85fccc
commit 22bdf25e23
21 changed files with 620 additions and 18 deletions

View File

@ -69,7 +69,8 @@ class DataProcessingPanels(horizon.PanelGroup):
'data_processing.job_binaries',
'data_processing.data_sources',
'data_processing.data_image_registry',
'data_processing.data_plugins',)
'data_processing.data_plugins',
'data_processing.wizard',)
class Project(horizon.Dashboard):

View File

@ -166,28 +166,39 @@ class ConfigureNodegroupsAction(workflows.Action):
super(ConfigureNodegroupsAction, self). \
__init__(request, *args, **kwargs)
plugin, hadoop_version = whelpers.\
get_plugin_and_hadoop_version(request)
plugin = request.REQUEST.get("plugin_name")
version = request.REQUEST.get("hadoop_version")
if plugin and not version:
version_name = plugin + "_version"
version = request.REQUEST.get(version_name)
self.templates = saharaclient.nodegroup_template_find(
request, plugin_name=plugin, hadoop_version=hadoop_version)
if not plugin or not version:
self.templates = saharaclient.nodegroup_template_find(request)
else:
self.templates = saharaclient.nodegroup_template_find(
request, plugin_name=plugin, hadoop_version=version)
deletable = request.REQUEST.get("deletable", dict())
request_source = None
if 'forms_ids' in request.POST:
request_source = request.POST
elif 'forms_ids' in request.REQUEST:
request_source = request.REQUEST
if request_source:
self.groups = []
for id in json.loads(request.POST['forms_ids']):
for id in json.loads(request_source['forms_ids']):
group_name = "group_name_" + str(id)
template_id = "template_id_" + str(id)
count = "count_" + str(id)
serialized = "serialized_" + str(id)
self.groups.append({"name": request.POST[group_name],
"template_id": request.POST[template_id],
"count": request.POST[count],
self.groups.append({"name": request_source[group_name],
"template_id": request_source[template_id],
"count": request_source[count],
"id": id,
"deletable": deletable.get(
request.POST[group_name], "true"),
"serialized": request.POST[serialized]})
request_source[group_name], "true"),
"serialized": request_source[serialized]})
whelpers.build_node_group_fields(self,
group_name,
@ -233,7 +244,6 @@ class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
ConfigureClusterTemplate._cls_registry = set([])
hlps = helpers.Helpers(request)
plugin, hadoop_version = whelpers.\
get_plugin_and_hadoop_version(request)
general_parameters = hlps.get_cluster_general_configs(
@ -300,6 +310,13 @@ class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
node_groups,
context["anti_affinity_info"],
)
hlps = helpers.Helpers(request)
if hlps.is_from_guide():
request.session["guide_cluster_template_name"] = (
context["general_cluster_template_name"])
self.success_url = (
"horizon:project:data_processing.wizard:cluster_guide")
return True
except api_base.APIException as e:
self.error_description = str(e)

View File

@ -30,6 +30,12 @@ urlpatterns = patterns('',
url(r'^configure-cluster$',
views.ConfigureClusterView.as_view(),
name='configure-cluster'),
url(r'^configure-cluster'
'/(?P<plugin_name>[^/]+)'
'/(?P<hadoop_version>[^/]+)'
'/(?P<cluster_template_name>[^/]+)/$',
views.ConfigureClusterView.as_view(),
name='configure-cluster'),
url(r'^(?P<cluster_id>[^/]+)$',
views.ClusterDetailsView.as_view(),
name='details'),

View File

@ -79,6 +79,11 @@ class ConfigureClusterView(workflows.WorkflowView):
template_name = "project/data_processing.clusters/configure.html"
page_title = _("Configure Cluster")
def get_initial(self):
initial = super(ConfigureClusterView, self).get_initial()
initial.update(self.kwargs)
return initial
class ScaleClusterView(workflows.WorkflowView):
workflow_class = scale_flow.ScaleCluster

View File

@ -22,7 +22,7 @@ from openstack_dashboard.dashboards.project.data_processing.utils \
import openstack_dashboard.dashboards.project.data_processing.utils. \
workflow_helpers as whelpers
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _
from openstack_dashboard.api import sahara as saharaclient
@ -162,7 +162,19 @@ class GeneralConfigAction(workflows.Action):
choices.append(("", _("No Templates Available")))
# cluster_template_id comes from cluster templates table, when
# Create Cluster from template is clicked there
selected_template_id = request.REQUEST.get("cluster_template_id", None)
selected_template_name = None
resolver_match = urlresolvers.resolve(request.path)
if "cluster_template_name" in resolver_match.kwargs:
selected_template_name = (
resolver_match.kwargs["cluster_template_name"])
if selected_template_name:
for template in templates:
if template.name == selected_template_name:
selected_template_id = template.id
break
else:
selected_template_id = (
request.REQUEST.get("cluster_template_id", None))
for template in templates:
if template.id == selected_template_id:

View File

@ -31,6 +31,12 @@ urlpatterns = patterns('sahara.nodegroup_templates.views',
url(r'^configure-nodegroup-template$',
views.ConfigureNodegroupTemplateView.as_view(),
name='configure-nodegroup-template'),
url(r'^configure-nodegroup-template'
'/(?P<plugin_name>[^/]+)/'
'(?P<hadoop_version>[^/]+)/'
'(?P<guide_template_type>[^/]+)/$',
views.ConfigureNodegroupTemplateView.as_view(),
name='configure-nodegroup-template-defaults'),
url(r'^(?P<template_id>[^/]+)$',
views.NodegroupTemplateDetailsView.as_view(),
name='details'),

View File

@ -86,6 +86,11 @@ class ConfigureNodegroupTemplateView(workflows.WorkflowView):
"project/data_processing.nodegroup_templates/configure.html")
page_title = _("Create Node Group Template")
def get_initial(self):
initial = super(ConfigureNodegroupTemplateView, self).get_initial()
initial.update(self.kwargs)
return initial
class CopyNodegroupTemplateView(workflows.WorkflowView):
workflow_class = copy_flow.CopyNodegroupTemplate

View File

@ -13,7 +13,9 @@
import logging
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _
from saharaclient.api import base as api_base
from horizon import exceptions
@ -147,6 +149,13 @@ class GeneralConfigAction(workflows.Action):
for param in node_parameters:
self.fields[param.name] = workflow_helpers.build_control(param)
resolver_match = urlresolvers.resolve(request.path)
if "guide_template_type" in resolver_match.kwargs:
self.fields["guide_template_type"] = forms.CharField(
required=False,
widget=forms.HiddenInput(),
initial=resolver_match.kwargs["guide_template_type"])
def populate_flavor_choices(self, request, context):
flavors = nova_utils.flavor_list(request)
if flavors:
@ -314,7 +323,7 @@ class ConfigureNodegroupTemplate(workflow_helpers.ServiceParametersWorkflow,
volumes_availability_zone = \
context["general_volumes_availability_zone"]
saharaclient.nodegroup_template_create(
ngt = saharaclient.nodegroup_template_create(
request,
name=context["general_nodegroup_name"],
plugin_name=plugin,
@ -330,6 +339,16 @@ class ConfigureNodegroupTemplate(workflow_helpers.ServiceParametersWorkflow,
security_groups=context["security_groups"],
auto_security_group=context["security_autogroup"],
availability_zone=context["general_availability_zone"])
hlps = helpers.Helpers(request)
if hlps.is_from_guide():
guide_type = context["general_guide_template_type"]
request.session[guide_type + "_name"] = (
context["general_nodegroup_name"])
request.session[guide_type + "_id"] = ngt.id
self.success_url = (
"horizon:project:data_processing.wizard:cluster_guide")
return True
except api_base.APIException as e:
self.error_description = str(e)

View File

@ -84,3 +84,23 @@ class Helpers(object):
'cluster', service)
return parameters
def is_from_guide(self):
referer = self.request.environ.get("HTTP_REFERER")
if referer and "/wizard/" in referer:
return True
return False
def reset_guide(self):
try:
self.request.session.update(
{"plugin_name": None,
"plugin_version": None,
"master_name": None,
"master_id": None,
"worker_name": None,
"worker_id": None,
"guide_cluster_template_name": None})
except Exception:
return False
return True

View File

@ -10,9 +10,9 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _
from horizon import forms
@ -163,8 +163,13 @@ def get_security_groups(request, security_group_ids):
def get_plugin_and_hadoop_version(request):
plugin_name = request.REQUEST["plugin_name"]
hadoop_version = request.REQUEST["hadoop_version"]
if request.REQUEST.get("plugin_name"):
plugin_name = request.REQUEST["plugin_name"]
hadoop_version = request.REQUEST["hadoop_version"]
else:
resolver_match = urlresolvers.resolve(request.path)
plugin_name = resolver_match.kwargs["plugin_name"]
hadoop_version = resolver_match.kwargs["hadoop_version"]
return (plugin_name, hadoop_version)

View File

@ -0,0 +1,86 @@
# 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.
from django import template
from django.template import defaultfilters
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard.api import sahara as saharaclient
from openstack_dashboard.dashboards.project.data_processing.utils \
import helpers
class ChoosePluginForm(forms.SelfHandlingForm):
def __init__(self, request, *args, **kwargs):
super(ChoosePluginForm, self).__init__(request, *args, **kwargs)
self._generate_plugin_version_fields(request)
self.help_text_template = ("project/data_processing.wizard/"
"_plugin_select_help.html")
def handle(self, request, context):
try:
hlps = helpers.Helpers(request)
hlps.reset_guide()
plugin_name = context["plugin_name"]
request.session["plugin_name"] = plugin_name
request.session["plugin_version"] = (
context[plugin_name + "_version"])
messages.success(request, "Cluster type chosen")
return True
except Exception:
exceptions.handle(request,
_("Unable to set cluster type"))
return False
def _generate_plugin_version_fields(self, request):
sahara = saharaclient.client(request)
plugins = sahara.plugins.list()
plugin_choices = [(plugin.name, plugin.title) for plugin in plugins]
self.fields["plugin_name"] = forms.ChoiceField(
label=_("Plugin Name"),
choices=plugin_choices,
widget=forms.Select(attrs={"class": "switchable",
"data-slug": "plugin"}))
for plugin in plugins:
field_name = plugin.name + "_version"
choice_field = forms.ChoiceField(
label=_("Version"),
required=False,
choices=[(version, version) for version in plugin.versions],
widget=forms.Select(
attrs={"class": "switched",
"data-switch-on": "plugin",
"data-plugin-" + plugin.name: plugin.title})
)
self.fields[field_name] = choice_field
def get_help_text(self, extra_context=None):
text = ""
extra_context = extra_context or {}
if self.help_text_template:
tmpl = template.loader.get_template(self.help_text_template)
context = template.RequestContext(self.request, extra_context)
text += tmpl.render(context)
else:
text += defaultfilters.linebreaks(force_text(self.help_text))
return defaultfilters.safe(text)
class Meta(object):
name = _("Choose plugin type and version")

View File

@ -0,0 +1,27 @@
# 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.
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.dashboards.project import dashboard
class WizardPanel(horizon.Panel):
name = _("Guides")
slug = 'data_processing.wizard'
permissions = ('openstack.services.data-processing',)
dashboard.Project.register(WizardPanel)

View File

@ -0,0 +1,31 @@
{% extends "horizon/common/_modal_form.html" %}
{% load url from future %}
{% load i18n %}
{% block form_id %}create-job-binary{% endblock %}
{% block form_action %}
{% url 'horizon:project:data_processing.wizard:plugin_select' %}
{% endblock %}
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
{% block modal-header %}{% trans "Choose plugin and version" %}{% endblock %}
{% block modal-body %}
<div class="left">
<fieldset>
{% include "horizon/common/_form_fields.html" %}
</fieldset>
</div>
<div class="form-help-block right">
{{ form.get_help_text }}
</div>
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary pull-right" id="plugin_select_btn"
type="submit" value="{% trans "Select" %}"/>
<a href="{% url 'horizon:project:data_processing.wizard:cluster_guide' %}"
class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% load i18n horizon %}
<p class="well">
{% blocktrans %}Select which plugin and version that you
want to use to create your cluster.{% endblocktrans %}
</p>

View File

@ -0,0 +1,168 @@
{% extends 'base.html' %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans "Data Processing" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Guided Cluster Creation") %}
{% endblock page_header %}
{% block main %}
<div class="guide">
<ol>
<li>
<div>
<div>{% blocktrans %}The first step is to determine which type of
cluster you want to run. You may have several choices
available depending on the configuration of your system.
Click on "choose plugin" to bring up the list of data
processing plugins. There you will be able to choose the
data processing plugin along with the version number.
Choosing this up front will allow the rest of the cluster
creation steps to focus only on options that are pertinent
to your desired cluster type.{% endblocktrans %}
</div>
<a class="btn btn-default btn-small btn-create btn-inline ajax-modal" href="
{% url 'horizon:project:data_processing.wizard:plugin_select' %}">{% trans "Choose plugin" %}</a>
<div>{% trans "Current choice:" %}
{% if request.session.plugin_name and request.session.plugin_version %}
<span class="text-success">
{% trans "Plugin:" %}
{{ request.session.plugin_name }}
{% trans "Version:" %}
{{ request.session.plugin_version }}
</span>
{% else %}
<span class="text-danger">
{% trans "No plugin chosen" %}
</span>
{% endif %}
</div>
</div>
</li>
<hr/>
<li>
<div>
<div>{% blocktrans %}Next, you need to define the different
types of machines in your cluster. This is done by
defining a Node Group Template for each type of
machine. A very common case is where you
need to have one or more machines running a "master"
set of processes while another set of machines need
to be running the "worker" processes. Here,
you will define the Node Group Template for your
"master" node(s).
{% endblocktrans %}
</div>
<div>
<a class="btn btn-default btn-small btn-create btn-inline ajax-modal
{% if not request.session.plugin_name or not request.session.plugin_version %} disabled {% endif %}"
href="{% if request.session.plugin_name and request.session.plugin_version %}{% url 'horizon:project:data_processing.nodegroup_templates:configure-nodegroup-template-defaults' request.session.plugin_name request.session.plugin_version 'master' %}{% endif %}">
<span class="fa fa-plus"></span> {% trans "Create a Master Node Group Template" %}</a>
</div>
<div>{% trans "Current choice:" %}
{% if request.session.master_name %}
<span class="text-success">
{% trans "Master Node Group Template:" %}
{{ request.session.master_name }}
</span>
{% else %}
<span class="text-danger">
{% trans "No Master Node Group Template Created" %}
</span>
{% endif %}
</div>
</div>
</li>
<hr/>
<li>
<div>
<div>{% blocktrans %}Repeat the Node Group Template
creation process, but this time you are creating
your "worker" Node Group Template.{% endblocktrans %}
</div>
<div>
<a class="btn btn-default btn-small btn-create btn-inline ajax-modal
{% if not request.session.master_name %} disabled{% endif %}"
href="{% if request.session.plugin_name and request.session.plugin_version %}{% url 'horizon:project:data_processing.nodegroup_templates:configure-nodegroup-template-defaults' request.session.plugin_name request.session.plugin_version 'worker' %}{% endif %}">
<span class="fa fa-plus"></span> {% trans "Create a Worker Node Group Template" %}</a>
</div>
<div>{% trans "Current choice:" %}
{% if request.session.worker_name %}
<span class="text-success">
{% trans "Worker Node Group Template:" %}
{{ request.session.worker_name }}
</span>
{% else %}
<span class="text-danger">
{% trans "No Worker Node Group Template Created" %}
</span>
{% endif %}
</div>
</div>
</li>
<hr/>
<li>
<div>
<div>{% blocktrans %}Now you need to set the layout of your
cluster. By
creating a Cluster Template, you will be choosing the
number of instances of each Node Group Template that
will appear in your cluster. Additionally,
you will have a chance to set any cluster-specific
configuration items in the additional tabs on the
create Cluster Template form.{% endblocktrans %}
</div>
<div>
<a class="btn btn-default btn-small btn-create btn-inline ajax-modal
{% if not request.session.worker_name %} disabled{% endif %}"
href="{% url 'horizon:project:data_processing.cluster_templates:configure-cluster-template' %}?plugin_name={{ request.session.plugin_name }}&hadoop_version={{ request.session.plugin_version }}&forms_ids=[0,1]&count_0=1&group_name_0={{ request.session.master_name }}&template_id_0={{ request.session.master_id }}&count_1=1&group_name_1={{ request.session.worker_name }}&template_id_1={{ request.session.worker_id }}&serialized_0=null&serialized_1=null">
<span class="fa fa-plus"></span> {% trans "Create a Cluster Template" %}</a>
</div>
<div>{% trans "Current choice:" %}
{% if request.session.guide_cluster_template_name %}
<span class="text-success">
{% trans "Worker Node Group Template:" %}
{{ request.session.guide_cluster_template_name }}
</span>
{% else %}
<span class="text-danger">
{% trans "No Cluster Template Created" %}
</span>
{% endif %}
</div>
</div>
</li>
<hr/>
<li>
<div>
<div>{% blocktrans %}You are now ready to
launch your cluster. When you click on the link
below, you will need to give your cluster a name,
choose the Cluster Template to use and choose which
image to use to build your instances. After you
click on "Create", your instances will begin to
spawn. Your cluster should be operational in a few
minutes.{% endblocktrans %}
</div>
<div>
<a class="btn btn-default btn-small btn-create btn-inline ajax-modal
{% if not request.session.guide_cluster_template_name %} disabled{% endif %}"
href="{% if request.session.guide_cluster_template_name %}{% url 'horizon:project:data_processing.clusters:configure-cluster' request.session.plugin_name request.session.plugin_version request.session.guide_cluster_template_name%}{% endif %}">
<span class="fa fa-plus"></span> {% trans "Launch a Cluster" %}</a>
</div>
</div>
</li>
</ol>
<div>
<a id="reset_cluster_guide_btn"
class=" btn btn-default btn-small btn-create btn-inline btn-danger"
title="{% trans "Reset Cluster Guide" %}"
href="{% url 'horizon:project:data_processing.wizard:reset_cluster_guide' True %}">
{% trans "Reset Cluster Creation Guide" %}
</a>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Choose plugin and version" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Choose plugin and version") %}
{% endblock page_header %}
{% block main %}
{% include 'project/data_processing.wizard/_plugin_select.html' %}
{% endblock %}

View File

@ -0,0 +1,38 @@
{% extends 'base.html' %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans "Data Processing" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Data Processing Guides") %}
{% endblock page_header %}
{% block main %}
<div class="guide">
<ul>
<li>
<div>
<div>{% blocktrans %}
Each of the Data Processing frameworks require a cluster of machines
in order to do the work they are assigned. A cluster is
formed by creating a set of Node Group Templates, combining
those into a Cluster Template and then launching a Cluster.
You can do each of those steps manually, or you can follow
this guide to help take you through the steps of
Cluster creation.
{% endblocktrans %}
</div>
<div>
<a id="cluster_guide_btn"
class=" btn btn-default btn-small btn-create btn-inline"
title="{% trans "Cluster Guide" %}"
href="{% url 'horizon:project:data_processing.wizard:cluster_guide' %}">
{% trans "Cluster Creation Guide" %}
</a>
</div>
</div>
</li>
</ul>
{% endblock %}

View File

@ -0,0 +1,44 @@
# 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.
from django.core.urlresolvers import reverse
from openstack_dashboard.test import helpers as test
INDEX_URL = reverse(
'horizon:project:data_processing.wizard:index')
CLUSTER_GUIDE_URL = reverse(
'horizon:project:data_processing.wizard:cluster_guide')
CLUSTER_GUIDE_RESET_URL = reverse(
'horizon:project:data_processing.wizard:reset_cluster_guide',
kwargs={"reset_cluster_guide": "true"})
class DataProcessingClusterGuideTests(test.TestCase):
def test_index(self):
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(
res, 'project/data_processing.wizard/wizard.html')
self.assertContains(res, 'Data Processing Guides')
self.assertContains(res, 'Cluster Creation Guide')
def test_cluster_guide(self):
res = self.client.get(CLUSTER_GUIDE_URL)
self.assertTemplateUsed(
res, 'project/data_processing.wizard/cluster_guide.html')
self.assertContains(res, 'Guided Cluster Creation')
self.assertContains(res, 'Current choice')
def test_cluster_guide_reset(self):
res = self.client.get(CLUSTER_GUIDE_RESET_URL)
self.assertRedirectsNoFollow(res, CLUSTER_GUIDE_URL)

View File

@ -0,0 +1,32 @@
# 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.
from django.conf.urls import patterns
from django.conf.urls import url
from openstack_dashboard.dashboards.project. \
data_processing.wizard import views
urlpatterns = patterns('',
url(r'^$', views.WizardView.as_view(), name='index'),
url(r'^cluster_guide$',
views.ClusterGuideView.as_view(),
name='cluster_guide'),
url(r'^cluster_guide/(?P<reset_cluster_guide>[^/]+)/$',
views.ResetClusterGuideView.as_view(),
name='reset_cluster_guide'),
url(r'^plugin_select$',
views.PluginSelectView.as_view(),
name='plugin_select'),
)

View File

@ -0,0 +1,64 @@
# 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.
import logging
from django.core.urlresolvers import reverse_lazy
from django import http
from django.utils.translation import ugettext_lazy as _
from django.views import generic
from horizon import exceptions
from horizon import forms
from horizon import views as horizon_views
from openstack_dashboard.dashboards.project.data_processing.utils \
import helpers
import openstack_dashboard.dashboards.project.data_processing.wizard \
.forms as wizforms
LOG = logging.getLogger(__name__)
class WizardView(horizon_views.APIView):
template_name = 'project/data_processing.wizard/wizard.html'
def get_data(self, request, context, *args, **kwargs):
try:
context["test"] = "test data"
except Exception:
msg = _('Unable show guides.')
exceptions.handle(self.request, msg)
return context
class ClusterGuideView(horizon_views.APIView):
template_name = 'project/data_processing.wizard/cluster_guide.html'
class ResetClusterGuideView(generic.RedirectView):
pattern_name = 'horizon:project:data_processing.wizard:cluster_guide'
def get(self, request, *args, **kwargs):
if kwargs["reset_cluster_guide"]:
hlps = helpers.Helpers(request)
hlps.reset_guide()
return http.HttpResponseRedirect(reverse_lazy(self.pattern_name))
class PluginSelectView(forms.ModalFormView):
form_class = wizforms.ChoosePluginForm
success_url = reverse_lazy(
'horizon:project:data_processing.wizard:cluster_guide')
classes = ("ajax-modal")
template_name = "project/data_processing.wizard/plugin_select.html"