Repository cleanup
The dashboard is now available in Horizon under the data_processing module. Partially-implements bp: merge-sahara-dashboard-to-horizon Change-Id: Ic728f25dc337ccca56c4d147458d61dd20acaaea
This commit is contained in:
parent
c76ec6ee1f
commit
8706077667
17
README.rst
17
README.rst
|
@ -1,5 +1,20 @@
|
|||
OpenStack Dashboard plugin for Sahara project
|
||||
==============================================
|
||||
=============================================
|
||||
|
||||
NOTE:
|
||||
=====
|
||||
|
||||
Sahara Dashboard is now integrated into the Horizon project. http://github.com/openstack/horizon
|
||||
The panels can now be found in the data_processing module of Projects Dashboard.
|
||||
https://github.com/openstack/horizon/tree/master/openstack_dashboard/dashboards/project/data_processing
|
||||
|
||||
This repository will now contain only selenium based tests for the Data Processing Panels.
|
||||
|
||||
This change is not meant to be backported to stable/icehouse or any other tags or branches.
|
||||
So you can still use Sahara Dasboard as a separate dashboard with stable/icehouse version of Horizon.
|
||||
|
||||
Links:
|
||||
------
|
||||
|
||||
Sahara project: https://github.com/openstack/sahara
|
||||
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
pbr>=0.6,!=0.7,<1.0
|
||||
six>=1.7.0
|
||||
|
||||
python-saharaclient>=0.6.0
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import exceptions
|
||||
from saharaclient.api import base as api_base
|
||||
from saharaclient import client as api_client
|
||||
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
|
||||
# horizon.api is for backward compatibility with folsom
|
||||
base = importutils.import_any('openstack_dashboard.api.base',
|
||||
'horizon.api.base')
|
||||
|
||||
keystone = importutils.import_any('openstack_dashboard.api.keystone',
|
||||
'horizon.api.keystone')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_horizon_parameter(name, default_value):
|
||||
import openstack_dashboard.settings
|
||||
|
||||
if hasattr(openstack_dashboard.settings, name):
|
||||
return getattr(openstack_dashboard.settings, name)
|
||||
else:
|
||||
logging.info('Parameter %s is not found in local_settings.py, '
|
||||
'using default "%s"' % (name, default_value))
|
||||
return default_value
|
||||
|
||||
|
||||
# These parameters should be defined in Horizon's local_settings.py
|
||||
# Example SAHARA_URL - http://localhost:9000/v1.0
|
||||
SAHARA_URL = get_horizon_parameter('SAHARA_URL', None)
|
||||
# "type" of Sahara service registered in keystone
|
||||
SAHARA_SERVICE = get_horizon_parameter('SAHARA_SERVICE', 'data_processing')
|
||||
# hint to generate additional Neutron network field
|
||||
SAHARA_USE_NEUTRON = get_horizon_parameter('SAHARA_USE_NEUTRON', False)
|
||||
|
||||
AUTO_ASSIGNMENT_ENABLED = get_horizon_parameter('AUTO_ASSIGNMENT_ENABLED',
|
||||
True)
|
||||
|
||||
exceptions.RECOVERABLE += (api_base.APIException,)
|
||||
|
||||
|
||||
def get_sahara_url(request):
|
||||
if SAHARA_URL is not None:
|
||||
url = SAHARA_URL.rstrip('/')
|
||||
if url.split('/')[-1] in ['v1.0', 'v1.1']:
|
||||
url = SAHARA_URL + '/' + request.user.tenant_id
|
||||
return url
|
||||
|
||||
return base.url_for(request, SAHARA_SERVICE)
|
||||
|
||||
|
||||
def client(request):
|
||||
endpoint_type = get_horizon_parameter('OPENSTACK_ENDPOINT_TYPE',
|
||||
'internalURL')
|
||||
auth_url = keystone._get_endpoint_url(request, endpoint_type)
|
||||
return api_client.Client('1.1', sahara_url=get_sahara_url(request),
|
||||
service_type=SAHARA_SERVICE,
|
||||
project_id=request.user.tenant_id,
|
||||
input_auth_token=request.user.token.id,
|
||||
auth_url=auth_url)
|
|
@ -1,76 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from saharadashboard.utils import workflow_helpers as work_helpers
|
||||
|
||||
|
||||
class Helpers(object):
|
||||
def __init__(self, sahara_client):
|
||||
self.sahara = sahara_client
|
||||
self.plugins = self.sahara.plugins
|
||||
|
||||
def _get_node_processes(self, plugin):
|
||||
processes = []
|
||||
for proc_lst in plugin.node_processes.values():
|
||||
processes += proc_lst
|
||||
|
||||
return [(proc_name, proc_name) for proc_name in processes]
|
||||
|
||||
def get_node_processes(self, plugin_name, hadoop_version):
|
||||
plugin = self.plugins.get_version_details(plugin_name, hadoop_version)
|
||||
|
||||
return self._get_node_processes(plugin)
|
||||
|
||||
def _extract_parameters(self, configs, scope, applicable_target):
|
||||
parameters = []
|
||||
for config in configs:
|
||||
if (config['scope'] == scope and
|
||||
config['applicable_target'] == applicable_target):
|
||||
|
||||
parameters.append(work_helpers.Parameter(config))
|
||||
|
||||
return parameters
|
||||
|
||||
def get_cluster_general_configs(self, plugin_name, hadoop_version):
|
||||
plugin = self.plugins.get_version_details(plugin_name, hadoop_version)
|
||||
|
||||
return self._extract_parameters(plugin.configs, 'cluster', "general")
|
||||
|
||||
def get_general_node_group_configs(self, plugin_name, hadoop_version):
|
||||
plugin = self.plugins.get_version_details(plugin_name, hadoop_version)
|
||||
|
||||
return self._extract_parameters(plugin.configs, 'node', 'general')
|
||||
|
||||
def get_targeted_node_group_configs(self, plugin_name, hadoop_version):
|
||||
plugin = self.plugins.get_version_details(plugin_name, hadoop_version)
|
||||
|
||||
parameters = {}
|
||||
|
||||
for service in plugin.node_processes.keys():
|
||||
parameters[service] = self._extract_parameters(plugin.configs,
|
||||
'node', service)
|
||||
|
||||
return parameters
|
||||
|
||||
def get_targeted_cluster_configs(self, plugin_name, hadoop_version):
|
||||
plugin = self.plugins.get_version_details(plugin_name, hadoop_version)
|
||||
|
||||
parameters = {}
|
||||
|
||||
for service in plugin.node_processes.keys():
|
||||
parameters[service] = self._extract_parameters(plugin.configs,
|
||||
'cluster', service)
|
||||
|
||||
return parameters
|
|
@ -1,58 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
from saharadashboard.utils import workflow_helpers
|
||||
|
||||
|
||||
class UploadFileForm(forms.SelfHandlingForm,
|
||||
workflow_helpers.PluginAndVersionMixin):
|
||||
template_name = forms.CharField(max_length=80,
|
||||
label=_("Cluster Template Name"))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(UploadFileForm, self).__init__(request, *args, **kwargs)
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
self._generate_plugin_version_fields(sahara)
|
||||
|
||||
self.fields['template_file'] = forms.FileField(label=_("Template"),
|
||||
required=True)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
# we can set a limit on file size, but should we?
|
||||
filecontent = self.files['template_file'].read()
|
||||
|
||||
plugin_name = data['plugin_name']
|
||||
hadoop_version = data.get(plugin_name + "_version")
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
sahara.plugins.convert_to_cluster_template(plugin_name,
|
||||
hadoop_version,
|
||||
data['template_name'],
|
||||
filecontent)
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
messages.error(request, str(e))
|
||||
return False
|
||||
except Exception as e:
|
||||
messages.error(request, str(e))
|
||||
return True
|
|
@ -1,27 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class ClusterTemplatesPanel(horizon.Panel):
|
||||
name = _("Cluster Templates")
|
||||
slug = 'cluster_templates'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(ClusterTemplatesPanel)
|
|
@ -1,120 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.core import urlresolvers
|
||||
from django import template
|
||||
from django.utils import http
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def render_node_groups(cluster_template):
|
||||
template_name = 'cluster_templates/_nodegroups_list.html'
|
||||
context = {"node_groups": cluster_template.node_groups}
|
||||
return template.loader.render_to_string(template_name, context)
|
||||
|
||||
|
||||
class UploadFile(tables.LinkAction):
|
||||
name = 'upload_file'
|
||||
verbose_name = _("Upload Template")
|
||||
url = 'horizon:sahara:cluster_templates:upload_file'
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
|
||||
class CreateCluster(tables.LinkAction):
|
||||
name = "create cluster"
|
||||
verbose_name = _("Launch Cluster")
|
||||
url = "horizon:sahara:clusters:configure-cluster"
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = urlresolvers.reverse(self.url)
|
||||
|
||||
params = http.urlencode({"hadoop_version": datum.hadoop_version,
|
||||
"plugin_name": datum.plugin_name,
|
||||
"cluster_template_id": datum.id})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
|
||||
class CopyTemplate(tables.LinkAction):
|
||||
name = "copy"
|
||||
verbose_name = _("Copy Template")
|
||||
url = "horizon:sahara:cluster_templates:copy"
|
||||
classes = ("ajax-modal", )
|
||||
|
||||
|
||||
class DeleteTemplate(tables.BatchAction):
|
||||
name = "delete_cluster_template"
|
||||
verbose_name = _("Delete Template")
|
||||
classes = ("btn-terminate", "btn-danger")
|
||||
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Template")
|
||||
data_type_plural = _("Templates")
|
||||
|
||||
def allowed(self, request, template):
|
||||
return True
|
||||
|
||||
def action(self, request, template_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.cluster_templates.delete(template_id)
|
||||
|
||||
|
||||
class CreateClusterTemplate(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Template")
|
||||
url = "horizon:sahara:cluster_templates:create-cluster-template"
|
||||
classes = ("ajax-modal", "btn-create", "create-clustertemplate-btn")
|
||||
|
||||
|
||||
class ConfigureClusterTemplate(tables.LinkAction):
|
||||
name = "configure"
|
||||
verbose_name = _("Configure Cluster Template")
|
||||
url = "horizon:sahara:cluster_templates:configure-cluster-template"
|
||||
classes = ("ajax-modal", "btn-create", "configure-clustertemplate-btn")
|
||||
attrs = {"style": "display: none"}
|
||||
|
||||
|
||||
class ClusterTemplatesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:cluster_templates:details"))
|
||||
plugin_name = tables.Column("plugin_name",
|
||||
verbose_name=_("Plugin"))
|
||||
hadoop_version = tables.Column("hadoop_version",
|
||||
verbose_name=_("Hadoop Version"))
|
||||
node_groups = tables.Column(render_node_groups,
|
||||
verbose_name=_("Node Groups"))
|
||||
description = tables.Column("description",
|
||||
verbose_name=_("Description"))
|
||||
|
||||
class Meta:
|
||||
name = "cluster_templates"
|
||||
verbose_name = _("Cluster Templates")
|
||||
table_actions = (UploadFile,
|
||||
CreateClusterTemplate,
|
||||
ConfigureClusterTemplate,
|
||||
DeleteTemplate,)
|
||||
|
||||
row_actions = (CreateCluster,
|
||||
CopyTemplate,
|
||||
DeleteTemplate,)
|
|
@ -1,64 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.utils import importutils
|
||||
from saharadashboard.utils import workflow_helpers as helpers
|
||||
nova = importutils.import_any('openstack_dashboard.api.nova',
|
||||
'horizon.api.nova')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "cluster_template_details_tab"
|
||||
template_name = ("cluster_templates/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
template_id = self.tab_group.kwargs['template_id']
|
||||
sahara = saharaclient(request)
|
||||
template = sahara.cluster_templates.get(template_id)
|
||||
return {"template": template}
|
||||
|
||||
|
||||
class NodeGroupsTab(tabs.Tab):
|
||||
name = _("Node Groups")
|
||||
slug = "cluster_template_nodegroups_tab"
|
||||
template_name = ("cluster_templates/_nodegroups_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
template_id = self.tab_group.kwargs['template_id']
|
||||
sahara = saharaclient(request)
|
||||
template = sahara.cluster_templates.get(template_id)
|
||||
for ng in template.node_groups:
|
||||
if not ng["flavor_id"]:
|
||||
continue
|
||||
ng["flavor_name"] = nova.flavor_get(request, ng["flavor_id"]).name
|
||||
ng["node_group_template"] = helpers.safe_call(
|
||||
sahara.node_group_templates.get,
|
||||
ng.get("node_group_template_id", None))
|
||||
return {"template": template}
|
||||
|
||||
|
||||
class ClusterTemplateDetailsTabs(tabs.TabGroup):
|
||||
slug = "cluster_template_details"
|
||||
tabs = (GeneralTab, NodeGroupsTab, )
|
||||
sticky = True
|
|
@ -1,45 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
import saharadashboard.cluster_templates.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.ClusterTemplatesView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.ClusterTemplatesView.as_view(),
|
||||
name='cluster-templates'),
|
||||
url(r'^upload_file$',
|
||||
views.UploadFileView.as_view(),
|
||||
name='upload_file'),
|
||||
url(r'^create-cluster-template$',
|
||||
views.CreateClusterTemplateView.as_view(),
|
||||
name='create-cluster-template'),
|
||||
url(r'^configure-cluster-template$',
|
||||
views.ConfigureClusterTemplateView.as_view(),
|
||||
name='configure-cluster-template'),
|
||||
url(r'^(?P<template_id>[^/]+)$',
|
||||
views.ClusterTemplateDetailsView.as_view(),
|
||||
name='details'),
|
||||
url(r'^(?P<template_id>[^/]+)/copy$',
|
||||
views.CopyClusterTemplateView.as_view(),
|
||||
name='copy'))
|
|
@ -1,100 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.cluster_templates import forms as cluster_forms
|
||||
from saharadashboard.cluster_templates.tables import ClusterTemplatesTable
|
||||
import saharadashboard.cluster_templates.tabs as _tabs
|
||||
import saharadashboard.cluster_templates.workflows.copy as copy_flow
|
||||
import saharadashboard.cluster_templates.workflows.create as create_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClusterTemplatesView(tables.DataTableView):
|
||||
table_class = ClusterTemplatesTable
|
||||
template_name = 'cluster_templates/cluster_templates.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
cluster_templates = sahara.cluster_templates.list()
|
||||
return cluster_templates
|
||||
|
||||
|
||||
class ClusterTemplateDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.ClusterTemplateDetailsTabs
|
||||
template_name = 'cluster_templates/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ClusterTemplateDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
class UploadFileView(forms.ModalFormView):
|
||||
form_class = cluster_forms.UploadFileForm
|
||||
template_name = 'cluster_templates/upload_file.html'
|
||||
success_url = reverse_lazy('horizon:sahara:cluster_templates:index')
|
||||
|
||||
|
||||
class CreateClusterTemplateView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.CreateClusterTemplate
|
||||
success_url = \
|
||||
"horizon:sahara:cluster_templates:create-cluster-template"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "cluster_templates/create.html"
|
||||
|
||||
|
||||
class ConfigureClusterTemplateView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.ConfigureClusterTemplate
|
||||
success_url = "horizon:sahara:cluster_templates"
|
||||
template_name = "cluster_templates/configure.html"
|
||||
|
||||
|
||||
class CopyClusterTemplateView(workflows.WorkflowView):
|
||||
workflow_class = copy_flow.CopyClusterTemplate
|
||||
success_url = "horizon:sahara:cluster_templates"
|
||||
template_name = "cluster_templates/configure.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CopyClusterTemplateView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
|
||||
context["template_id"] = kwargs["template_id"]
|
||||
return context
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
template_id = self.kwargs['template_id']
|
||||
sahara = saharaclient(self.request)
|
||||
template = sahara.cluster_templates.get(template_id)
|
||||
self._object = template
|
||||
return self._object
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(CopyClusterTemplateView, self).get_initial()
|
||||
initial.update({'template_id': self.kwargs['template_id']})
|
||||
return initial
|
|
@ -1,78 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.cluster_templates.workflows.create as create_flow
|
||||
from saharadashboard.utils.workflow_helpers import build_node_group_fields
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CopyClusterTemplate(create_flow.ConfigureClusterTemplate):
|
||||
success_message = _("Cluster Template copy %s created")
|
||||
|
||||
def __init__(self, request, context_seed, entry_point, *args, **kwargs):
|
||||
sahara = saharaclient(request)
|
||||
|
||||
template_id = context_seed["template_id"]
|
||||
template = sahara.cluster_templates.get(template_id)
|
||||
self._set_configs_to_copy(template.cluster_configs)
|
||||
|
||||
request.GET = request.GET.copy()
|
||||
request.GET.update({"plugin_name": template.plugin_name})
|
||||
request.GET.update({"hadoop_version": template.hadoop_version})
|
||||
request.GET.update({"aa_groups": template.anti_affinity})
|
||||
|
||||
super(CopyClusterTemplate, self).__init__(request, context_seed,
|
||||
entry_point, *args,
|
||||
**kwargs)
|
||||
|
||||
# init Node Groups
|
||||
|
||||
for step in self.steps:
|
||||
if isinstance(step, create_flow.ConfigureNodegroups):
|
||||
ng_action = step.action
|
||||
template_ngs = template.node_groups
|
||||
|
||||
if 'forms_ids' not in request.POST:
|
||||
ng_action.groups = []
|
||||
for id in range(0, len(template_ngs), 1):
|
||||
group_name = "group_name_" + str(id)
|
||||
template_id = "template_id_" + str(id)
|
||||
count = "count_" + str(id)
|
||||
templ_ng = template_ngs[id]
|
||||
ng_action.groups.append(
|
||||
{"name": templ_ng["name"],
|
||||
"template_id": templ_ng["node_group_template_id"],
|
||||
"count": templ_ng["count"],
|
||||
"id": id,
|
||||
"deletable": "true"})
|
||||
|
||||
build_node_group_fields(ng_action,
|
||||
group_name,
|
||||
template_id,
|
||||
count)
|
||||
|
||||
elif isinstance(step, create_flow.GeneralConfig):
|
||||
fields = step.action.fields
|
||||
|
||||
fields["cluster_template_name"].initial = \
|
||||
template.name + "-copy"
|
||||
|
||||
fields["description"].initial = template.description
|
|
@ -1,299 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
from saharadashboard.api import helpers as helpers
|
||||
from saharadashboard.utils import anti_affinity as aa
|
||||
import saharadashboard.utils.workflow_helpers as whelpers
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SelectPluginAction(workflows.Action):
|
||||
hidden_create_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SelectPluginAction, self).__init__(request, *args, **kwargs)
|
||||
|
||||
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"),
|
||||
required=True,
|
||||
choices=plugin_choices,
|
||||
widget=forms.Select(attrs={"class": "plugin_name_choice"}))
|
||||
|
||||
for plugin in plugins:
|
||||
field_name = plugin.name + "_version"
|
||||
choice_field = forms.ChoiceField(
|
||||
label=_("Hadoop version"),
|
||||
required=True,
|
||||
choices=[(version, version) for version in plugin.versions],
|
||||
widget=forms.Select(
|
||||
attrs={"class": "plugin_version_choice "
|
||||
+ field_name + "_choice"})
|
||||
)
|
||||
self.fields[field_name] = choice_field
|
||||
|
||||
class Meta:
|
||||
name = _("Select plugin and hadoop version for cluster template")
|
||||
help_text_template = ("cluster_templates/_create_general_help.html")
|
||||
|
||||
|
||||
class SelectPlugin(workflows.Step):
|
||||
action_class = SelectPluginAction
|
||||
|
||||
|
||||
class CreateClusterTemplate(workflows.Workflow):
|
||||
slug = "create_cluster_template"
|
||||
name = _("Create Cluster Template")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created")
|
||||
failure_message = _("Could not create")
|
||||
success_url = "horizon:sahara:cluster_templates:index"
|
||||
default_steps = (SelectPlugin,)
|
||||
|
||||
|
||||
class GeneralConfigAction(workflows.Action):
|
||||
hidden_configure_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_configure_field"}))
|
||||
|
||||
hidden_to_delete_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_to_delete_field"}))
|
||||
|
||||
cluster_template_name = forms.CharField(label=_("Template Name"),
|
||||
required=True)
|
||||
|
||||
description = forms.CharField(label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
anti_affinity = aa.anti_affinity_field()
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
self.fields["plugin_name"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=plugin
|
||||
)
|
||||
self.fields["hadoop_version"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=hadoop_version
|
||||
)
|
||||
|
||||
populate_anti_affinity_choices = aa.populate_anti_affinity_choices
|
||||
|
||||
def get_help_text(self):
|
||||
extra = dict()
|
||||
plugin, hadoop_version = whelpers\
|
||||
.get_plugin_and_hadoop_version(self.request)
|
||||
|
||||
extra["plugin_name"] = plugin
|
||||
extra["hadoop_version"] = hadoop_version
|
||||
return super(GeneralConfigAction, self).get_help_text(extra)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(GeneralConfigAction, self).clean()
|
||||
if cleaned_data.get("hidden_configure_field", None) \
|
||||
== "create_nodegroup":
|
||||
self._errors = dict()
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
name = _("Details")
|
||||
help_text_template = \
|
||||
("cluster_templates/_configure_general_help.html")
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
contributes = ("hidden_configure_field", )
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context["general_" + k] = v
|
||||
|
||||
post = self.workflow.request.POST
|
||||
context['anti_affinity_info'] = post.getlist("anti_affinity")
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class ConfigureNodegroupsAction(workflows.Action):
|
||||
hidden_nodegroups_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_nodegroups_field"}))
|
||||
forms_ids = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(ConfigureNodegroupsAction, self). \
|
||||
__init__(request, *args, **kwargs)
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
self.templates = sahara.node_group_templates.find(
|
||||
plugin_name=plugin,
|
||||
hadoop_version=hadoop_version)
|
||||
|
||||
deletable = request.REQUEST.get("deletable", dict())
|
||||
|
||||
if 'forms_ids' in request.POST:
|
||||
self.groups = []
|
||||
for id in json.loads(request.POST['forms_ids']):
|
||||
group_name = "group_name_" + str(id)
|
||||
template_id = "template_id_" + str(id)
|
||||
count = "count_" + str(id)
|
||||
self.groups.append({"name": request.POST[group_name],
|
||||
"template_id": request.POST[template_id],
|
||||
"count": request.POST[count],
|
||||
"id": id,
|
||||
"deletable": deletable.get(
|
||||
request.POST[group_name], "true")})
|
||||
|
||||
whelpers.build_node_group_fields(self,
|
||||
group_name,
|
||||
template_id,
|
||||
count)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(ConfigureNodegroupsAction, self).clean()
|
||||
if cleaned_data.get("hidden_nodegroups_field", None) \
|
||||
== "create_nodegroup":
|
||||
self._errors = dict()
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
name = _("Node Groups")
|
||||
|
||||
|
||||
class ConfigureNodegroups(workflows.Step):
|
||||
action_class = ConfigureNodegroupsAction
|
||||
contributes = ("hidden_nodegroups_field", )
|
||||
template_name = "cluster_templates/cluster_node_groups_template.html"
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context["ng_" + k] = v
|
||||
return context
|
||||
|
||||
|
||||
class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
|
||||
whelpers.StatusFormatMixin):
|
||||
slug = "configure_cluster_template"
|
||||
name = _("Create Cluster Template")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created Cluster Template %s")
|
||||
name_property = "general_cluster_template_name"
|
||||
success_url = "horizon:sahara:cluster_templates:index"
|
||||
default_steps = (GeneralConfig,
|
||||
ConfigureNodegroups)
|
||||
|
||||
def __init__(self, request, context_seed, entry_point, *args, **kwargs):
|
||||
ConfigureClusterTemplate._cls_registry = set([])
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
hlps = helpers.Helpers(sahara)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
general_parameters = hlps.get_cluster_general_configs(
|
||||
plugin,
|
||||
hadoop_version)
|
||||
service_parameters = hlps.get_targeted_cluster_configs(
|
||||
plugin,
|
||||
hadoop_version)
|
||||
|
||||
self._populate_tabs(general_parameters, service_parameters)
|
||||
|
||||
super(ConfigureClusterTemplate, self).__init__(request,
|
||||
context_seed,
|
||||
entry_point,
|
||||
*args, **kwargs)
|
||||
|
||||
def is_valid(self):
|
||||
steps_valid = True
|
||||
for step in self.steps:
|
||||
if not step.action.is_valid():
|
||||
steps_valid = False
|
||||
step.has_errors = True
|
||||
errors_fields = []
|
||||
for k, v in step.action.errors.items():
|
||||
errors_fields.append(k)
|
||||
step.action.errors_fields = errors_fields
|
||||
if not steps_valid:
|
||||
return steps_valid
|
||||
return self.validate(self.context)
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
sahara = saharaclient.client(request)
|
||||
node_groups = []
|
||||
configs_dict = whelpers.parse_configs_from_context(context,
|
||||
self.defaults)
|
||||
|
||||
ids = json.loads(context['ng_forms_ids'])
|
||||
for id in ids:
|
||||
name = context['ng_group_name_' + str(id)]
|
||||
template_id = context['ng_template_id_' + str(id)]
|
||||
count = context['ng_count_' + str(id)]
|
||||
|
||||
ng = {"name": name,
|
||||
"node_group_template_id": template_id,
|
||||
"count": count}
|
||||
node_groups.append(ng)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
# TODO(nkonovalov): Fix client to support default_image_id
|
||||
sahara.cluster_templates.create(
|
||||
context["general_cluster_template_name"],
|
||||
plugin,
|
||||
hadoop_version,
|
||||
context["general_description"],
|
||||
configs_dict,
|
||||
node_groups,
|
||||
context["anti_affinity_info"])
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
self.error_description = str(e)
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
|
@ -1,27 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class ClustersPanel(horizon.Panel):
|
||||
name = _("Clusters")
|
||||
slug = 'clusters'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(ClustersPanel)
|
|
@ -1,114 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.http import Http404 # noqa
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateCluster(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Launch Cluster")
|
||||
url = "horizon:sahara:clusters:create-cluster"
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
|
||||
class ScaleCluster(tables.LinkAction):
|
||||
name = "scale"
|
||||
verbose_name = _("Scale Cluster")
|
||||
url = "horizon:sahara:clusters:scale"
|
||||
classes = ("ajax-modal", "btn-edit")
|
||||
|
||||
def allowed(self, request, cluster=None):
|
||||
return cluster.status == "Active"
|
||||
|
||||
|
||||
class DeleteCluster(tables.BatchAction):
|
||||
name = "delete"
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Cluster")
|
||||
data_type_plural = _("Clusters")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.clusters.delete(obj_id)
|
||||
|
||||
|
||||
class UpdateRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, instance_id):
|
||||
sahara = saharaclient(request)
|
||||
try:
|
||||
return sahara.clusters.get(instance_id)
|
||||
except api_base.APIException as e:
|
||||
if e.error_code == 404:
|
||||
# returning 404 to the ajax call removes the
|
||||
# row from the table on the ui
|
||||
raise Http404
|
||||
else:
|
||||
messages.error(request, e)
|
||||
|
||||
|
||||
def get_instances_count(cluster):
|
||||
return sum([len(ng["instances"])
|
||||
for ng in cluster.node_groups])
|
||||
|
||||
|
||||
class ConfigureCluster(tables.LinkAction):
|
||||
name = "configure"
|
||||
verbose_name = _("Configure Cluster")
|
||||
url = "horizon:sahara:clusters:configure-cluster"
|
||||
classes = ("ajax-modal", "btn-create", "configure-cluster-btn")
|
||||
attrs = {"style": "display: none"}
|
||||
|
||||
|
||||
class ClustersTable(tables.DataTable):
|
||||
STATUS_CHOICES = (
|
||||
("active", True),
|
||||
("error", False)
|
||||
)
|
||||
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:clusters:details"))
|
||||
status = tables.Column("status",
|
||||
verbose_name=_("Status"),
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES)
|
||||
instances_count = tables.Column(get_instances_count,
|
||||
verbose_name=_("Instances Count"))
|
||||
|
||||
class Meta:
|
||||
name = "clusters"
|
||||
verbose_name = _("Clusters")
|
||||
row_class = UpdateRow
|
||||
status_columns = ["status"]
|
||||
table_actions = (CreateCluster,
|
||||
ConfigureCluster,
|
||||
DeleteCluster)
|
||||
row_actions = (ScaleCluster,
|
||||
DeleteCluster,)
|
|
@ -1,154 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.utils import compatibility
|
||||
from saharadashboard.utils import importutils
|
||||
from saharadashboard.utils import workflow_helpers as helpers
|
||||
|
||||
neutron = importutils.import_any('openstack_dashboard.api.quantum',
|
||||
'horizon.api.quantum',
|
||||
'openstack_dashboard.api.neutron')
|
||||
nova = importutils.import_any('openstack_dashboard.api.nova',
|
||||
'horizon.api.nova')
|
||||
glance = importutils.import_any('openstack_dashboard.api.glance',
|
||||
'horizon.api.glance')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "cluster_details_tab"
|
||||
template_name = "clusters/_details.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
cluster_id = self.tab_group.kwargs['cluster_id']
|
||||
sahara = saharaclient(request)
|
||||
cluster = sahara.clusters.get(cluster_id)
|
||||
|
||||
for info_key, info_val in cluster.info.items():
|
||||
for key, val in info_val.items():
|
||||
if str(val).startswith(('http://', 'https://')):
|
||||
cluster.info[info_key][key] = build_link(val)
|
||||
|
||||
base_image = glance.image_get(request,
|
||||
cluster.default_image_id)
|
||||
|
||||
if getattr(cluster, 'cluster_template_id', None):
|
||||
cluster_template = helpers.safe_call(sahara.cluster_templates.get,
|
||||
cluster.cluster_template_id)
|
||||
else:
|
||||
cluster_template = None
|
||||
|
||||
if getattr(cluster, 'neutron_management_network', None):
|
||||
net_id = cluster.neutron_management_network
|
||||
network = neutron.network_get(request, net_id)
|
||||
network.set_id_as_name_if_empty()
|
||||
net_name = network.name
|
||||
else:
|
||||
net_name = None
|
||||
|
||||
return {"cluster": cluster,
|
||||
"base_image": base_image,
|
||||
"cluster_template": cluster_template,
|
||||
"network": net_name}
|
||||
|
||||
|
||||
def build_link(url):
|
||||
return "<a href='" + url + "' target=\"_blank\">" + url + "</a>"
|
||||
|
||||
|
||||
class NodeGroupsTab(tabs.Tab):
|
||||
name = _("Node Groups")
|
||||
slug = "cluster_nodegroups_tab"
|
||||
template_name = "clusters/_nodegroups_details.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
cluster_id = self.tab_group.kwargs['cluster_id']
|
||||
sahara = saharaclient(request)
|
||||
cluster = sahara.clusters.get(cluster_id)
|
||||
for ng in cluster.node_groups:
|
||||
if not ng["flavor_id"]:
|
||||
continue
|
||||
ng["flavor_name"] = nova.flavor_get(request, ng["flavor_id"]).name
|
||||
ng["node_group_template"] = helpers.safe_call(
|
||||
sahara.node_group_templates.get,
|
||||
ng.get("node_group_template_id", None))
|
||||
|
||||
return {"cluster": cluster}
|
||||
|
||||
|
||||
class Instance(object):
|
||||
def __init__(self, name=None, id=None, internal_ip=None,
|
||||
management_ip=None):
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.internal_ip = internal_ip
|
||||
self.management_ip = management_ip
|
||||
|
||||
|
||||
class InstancesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
link=(compatibility.convert_url(
|
||||
"horizon:project:instances:detail")),
|
||||
verbose_name=_("Name"))
|
||||
|
||||
internal_ip = tables.Column("internal_ip",
|
||||
verbose_name=_("Internal IP"))
|
||||
|
||||
management_ip = tables.Column("management_ip",
|
||||
verbose_name=_("Management IP"))
|
||||
|
||||
class Meta:
|
||||
name = "cluster_instances"
|
||||
# just ignoring the name
|
||||
verbose_name = _(" ")
|
||||
|
||||
|
||||
class InstancesTab(tabs.TableTab):
|
||||
name = _("Instances")
|
||||
slug = "cluster_instances_tab"
|
||||
template_name = "clusters/_instances_details.html"
|
||||
table_classes = (InstancesTable, )
|
||||
|
||||
def get_cluster_instances_data(self):
|
||||
cluster_id = self.tab_group.kwargs['cluster_id']
|
||||
sahara = saharaclient(self.request)
|
||||
cluster = sahara.clusters.get(cluster_id)
|
||||
|
||||
instances = []
|
||||
for ng in cluster.node_groups:
|
||||
for instance in ng["instances"]:
|
||||
instances.append(Instance(
|
||||
name=instance["instance_name"],
|
||||
id=instance["instance_id"],
|
||||
internal_ip=instance.get("internal_ip",
|
||||
"Not assigned"),
|
||||
management_ip=instance.get("management_ip",
|
||||
"Not assigned")))
|
||||
return instances
|
||||
|
||||
|
||||
class ClusterDetailsTabs(tabs.TabGroup):
|
||||
slug = "cluster_details"
|
||||
tabs = (GeneralTab, NodeGroupsTab, InstancesTab, )
|
||||
sticky = True
|
|
@ -1,42 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
import saharadashboard.clusters.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.ClustersView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.ClustersView.as_view(),
|
||||
name='clusters'),
|
||||
url(r'^create-cluster$',
|
||||
views.CreateClusterView.as_view(),
|
||||
name='create-cluster'),
|
||||
url(r'^configure-cluster$',
|
||||
views.ConfigureClusterView.as_view(),
|
||||
name='configure-cluster'),
|
||||
url(r'^(?P<cluster_id>[^/]+)$',
|
||||
views.ClusterDetailsView.as_view(),
|
||||
name='details'),
|
||||
url(r'^(?P<cluster_id>[^/]+)/scale$',
|
||||
views.ScaleClusterView.as_view(),
|
||||
name='scale'))
|
|
@ -1,92 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.clusters.tables import ClustersTable
|
||||
import saharadashboard.clusters.tabs as _tabs
|
||||
import saharadashboard.clusters.workflows.create as create_flow
|
||||
import saharadashboard.clusters.workflows.scale as scale_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ClustersView(tables.DataTableView):
|
||||
table_class = ClustersTable
|
||||
template_name = 'clusters/clusters.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
clusters = sahara.clusters.list()
|
||||
return clusters
|
||||
|
||||
|
||||
class ClusterDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.ClusterDetailsTabs
|
||||
template_name = 'clusters/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ClusterDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
class CreateClusterView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.CreateCluster
|
||||
success_url = \
|
||||
"horizon:sahara:clusters:create-cluster"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "clusters/create.html"
|
||||
|
||||
|
||||
class ConfigureClusterView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.ConfigureCluster
|
||||
success_url = "horizon:sahara:clusters"
|
||||
template_name = "clusters/configure.html"
|
||||
|
||||
|
||||
class ScaleClusterView(workflows.WorkflowView):
|
||||
workflow_class = scale_flow.ScaleCluster
|
||||
success_url = "horizon:sahara:clusters"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "clusters/scale.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ScaleClusterView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
|
||||
context["cluster_id"] = kwargs["cluster_id"]
|
||||
return context
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
template_id = self.kwargs['cluster_id']
|
||||
sahara = saharaclient(self.request)
|
||||
template = sahara.cluster_templates.get(template_id)
|
||||
self._object = template
|
||||
return self._object
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(ScaleClusterView, self).get_initial()
|
||||
initial.update({'cluster_id': self.kwargs['cluster_id']})
|
||||
return initial
|
|
@ -1,223 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
from saharadashboard.api.client import SAHARA_USE_NEUTRON
|
||||
import saharadashboard.cluster_templates.workflows.create as t_flows
|
||||
from saharadashboard.utils import importutils
|
||||
from saharadashboard.utils import neutron_support
|
||||
import saharadashboard.utils.workflow_helpers as whelpers
|
||||
|
||||
neutron = importutils.import_any('openstack_dashboard.api.quantum',
|
||||
'openstack_dashboard.api.neutron',
|
||||
'horizon.api.quantum',
|
||||
'horizon.api.neutron')
|
||||
|
||||
nova = importutils.import_any('openstack_dashboard.api.nova',
|
||||
'horizon.api.nova')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
KEYPAIR_IMPORT_URL = "horizon:project:access_and_security:keypairs:import"
|
||||
|
||||
|
||||
class SelectPluginAction(t_flows.SelectPluginAction):
|
||||
class Meta:
|
||||
name = _("Select plugin and hadoop version for cluster")
|
||||
help_text_template = ("clusters/_create_general_help.html")
|
||||
|
||||
|
||||
class SelectPlugin(t_flows.SelectPlugin):
|
||||
action_class = SelectPluginAction
|
||||
|
||||
|
||||
class CreateCluster(t_flows.CreateClusterTemplate):
|
||||
slug = "create_cluster"
|
||||
name = _("Launch Cluster")
|
||||
success_url = "horizon:sahara:cluster_templates:index"
|
||||
default_steps = (SelectPlugin,)
|
||||
|
||||
|
||||
class GeneralConfigAction(workflows.Action):
|
||||
hidden_configure_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_configure_field"}))
|
||||
|
||||
hidden_to_delete_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_to_delete_field"}))
|
||||
|
||||
cluster_name = forms.CharField(label=_("Cluster Name"),
|
||||
required=True)
|
||||
|
||||
description = forms.CharField(label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea)
|
||||
cluster_template = forms.ChoiceField(label=_("Cluster Template"),
|
||||
initial=(None, "None"),
|
||||
required=True)
|
||||
|
||||
image = forms.ChoiceField(label=_("Base Image"),
|
||||
required=True)
|
||||
|
||||
keypair = forms.DynamicChoiceField(
|
||||
label=_("Keypair"),
|
||||
required=False,
|
||||
help_text=_("Which keypair to use for authentication."),
|
||||
add_item_link=KEYPAIR_IMPORT_URL)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
if SAHARA_USE_NEUTRON:
|
||||
self.fields["neutron_management_network"] = forms.ChoiceField(
|
||||
label=_("Neutron Management Network"),
|
||||
required=True,
|
||||
choices=self.populate_neutron_management_network_choices(
|
||||
request, {})
|
||||
)
|
||||
|
||||
self.fields["plugin_name"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=plugin
|
||||
)
|
||||
self.fields["hadoop_version"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=hadoop_version
|
||||
)
|
||||
|
||||
def populate_image_choices(self, request, context):
|
||||
sahara = saharaclient.client(request)
|
||||
all_images = sahara.images.list()
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
details = sahara.plugins.get_version_details(plugin,
|
||||
hadoop_version)
|
||||
|
||||
return [(image.id, image.name) for image in all_images
|
||||
if set(details.required_image_tags).issubset(set(image.tags))]
|
||||
|
||||
def populate_keypair_choices(self, request, context):
|
||||
keypairs = nova.keypair_list(request)
|
||||
keypair_list = [(kp.name, kp.name) for kp in keypairs]
|
||||
keypair_list.insert(0, ("", "No keypair"))
|
||||
return keypair_list
|
||||
|
||||
def populate_cluster_template_choices(self, request, context):
|
||||
sahara = saharaclient.client(request)
|
||||
templates = sahara.cluster_templates.list()
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
choices = [(template.id, template.name)
|
||||
for template in templates
|
||||
if (template.hadoop_version == hadoop_version and
|
||||
template.plugin_name == plugin)]
|
||||
|
||||
# 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)
|
||||
|
||||
for template in templates:
|
||||
if template.id == selected_template_id:
|
||||
self.fields['cluster_template'].initial = template.id
|
||||
|
||||
return choices
|
||||
|
||||
populate_neutron_management_network_choices = \
|
||||
neutron_support.populate_neutron_management_network_choices
|
||||
|
||||
def get_help_text(self):
|
||||
extra = dict()
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(self.request)
|
||||
extra["plugin_name"] = plugin
|
||||
extra["hadoop_version"] = hadoop_version
|
||||
return super(GeneralConfigAction, self).get_help_text(extra)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(GeneralConfigAction, self).clean()
|
||||
if cleaned_data.get("hidden_configure_field", None) \
|
||||
== "create_nodegroup":
|
||||
self._errors = dict()
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
name = _("Configure Cluster")
|
||||
help_text_template = \
|
||||
("clusters/_configure_general_help.html")
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
contributes = ("hidden_configure_field", )
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context["general_" + k] = v
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class ConfigureCluster(whelpers.StatusFormatMixin, workflows.Workflow):
|
||||
slug = "configure_cluster"
|
||||
name = _("Launch Cluster")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created Cluster %s")
|
||||
name_property = "general_cluster_name"
|
||||
success_url = "horizon:sahara:clusters:index"
|
||||
default_steps = (GeneralConfig, )
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
sahara = saharaclient.client(request)
|
||||
# TODO(nkonovalov) Implement AJAX Node Groups
|
||||
node_groups = None
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
cluster_template_id = context["general_cluster_template"] or None
|
||||
user_keypair = context["general_keypair"] or None
|
||||
|
||||
sahara.clusters.create(
|
||||
context["general_cluster_name"],
|
||||
plugin, hadoop_version,
|
||||
cluster_template_id=cluster_template_id,
|
||||
default_image_id=context["general_image"],
|
||||
description=context["general_description"],
|
||||
node_groups=node_groups,
|
||||
user_keypair_id=user_keypair,
|
||||
net_id=context.get("general_neutron_management_network", None))
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
self.error_description = str(e)
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
|
@ -1,157 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import exceptions
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
import saharadashboard.cluster_templates.workflows.create as clt_create_flow
|
||||
import saharadashboard.clusters.workflows.create as cl_create_flow
|
||||
import saharadashboard.utils.workflow_helpers as whelpers
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NodeGroupsStep(clt_create_flow.ConfigureNodegroups):
|
||||
pass
|
||||
|
||||
|
||||
class ScaleCluster(cl_create_flow.ConfigureCluster,
|
||||
whelpers.StatusFormatMixin):
|
||||
slug = "scale_cluster"
|
||||
name = _("Scale Cluster")
|
||||
finalize_button_name = _("Scale")
|
||||
success_url = "horizon:sahara:clusters:index"
|
||||
default_steps = (NodeGroupsStep, )
|
||||
|
||||
def __init__(self, request, context_seed, entry_point, *args, **kwargs):
|
||||
ScaleCluster._cls_registry = set([])
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
|
||||
cluster_id = context_seed["cluster_id"]
|
||||
cluster = sahara.clusters.get(cluster_id)
|
||||
|
||||
self.success_message = "Scaling Cluster %s successfully started" \
|
||||
% cluster.name
|
||||
|
||||
plugin = cluster.plugin_name
|
||||
hadoop_version = cluster.hadoop_version
|
||||
|
||||
# init deletable nodegroups
|
||||
deletable = dict()
|
||||
for group in cluster.node_groups:
|
||||
deletable[group["name"]] = "false"
|
||||
|
||||
request.GET = request.GET.copy()
|
||||
request.GET.update({"cluster_id": cluster_id})
|
||||
request.GET.update({"plugin_name": plugin})
|
||||
request.GET.update({"hadoop_version": hadoop_version})
|
||||
request.GET.update({"deletable": deletable})
|
||||
|
||||
super(ScaleCluster, self).__init__(request, context_seed,
|
||||
entry_point, *args,
|
||||
**kwargs)
|
||||
|
||||
# init Node Groups
|
||||
|
||||
for step in self.steps:
|
||||
if isinstance(step, clt_create_flow.ConfigureNodegroups):
|
||||
ng_action = step.action
|
||||
template_ngs = cluster.node_groups
|
||||
|
||||
if 'forms_ids' not in request.POST:
|
||||
ng_action.groups = []
|
||||
for id in range(0, len(template_ngs), 1):
|
||||
group_name = "group_name_" + str(id)
|
||||
template_id = "template_id_" + str(id)
|
||||
count = "count_" + str(id)
|
||||
templ_ng = template_ngs[id]
|
||||
ng_action.groups.append(
|
||||
{"name": templ_ng["name"],
|
||||
"template_id": templ_ng["node_group_template_id"],
|
||||
"count": templ_ng["count"],
|
||||
"id": id,
|
||||
"deletable": "false"})
|
||||
|
||||
whelpers.build_node_group_fields(ng_action,
|
||||
group_name,
|
||||
template_id,
|
||||
count)
|
||||
|
||||
def format_status_message(self, message):
|
||||
# Scaling form requires special handling because it has no Cluster name
|
||||
# in it's context
|
||||
|
||||
error_description = getattr(self, 'error_description', None)
|
||||
if error_description:
|
||||
return error_description
|
||||
else:
|
||||
return self.success_message
|
||||
|
||||
def handle(self, request, context):
|
||||
sahara = saharaclient.client(request)
|
||||
cluster_id = request.GET["cluster_id"]
|
||||
cluster = sahara.clusters.get(cluster_id)
|
||||
|
||||
existing_node_groups = set([])
|
||||
for ng in cluster.node_groups:
|
||||
existing_node_groups.add(ng["name"])
|
||||
|
||||
scale_object = dict()
|
||||
|
||||
ids = json.loads(context["ng_forms_ids"])
|
||||
|
||||
for _id in ids:
|
||||
name = context["ng_group_name_%s" % _id]
|
||||
template_id = context["ng_template_id_%s" % _id]
|
||||
count = context["ng_count_%s" % _id]
|
||||
|
||||
if name not in existing_node_groups:
|
||||
if "add_node_groups" not in scale_object:
|
||||
scale_object["add_node_groups"] = []
|
||||
|
||||
scale_object["add_node_groups"].append(
|
||||
{"name": name,
|
||||
"node_group_template_id": template_id,
|
||||
"count": int(count)})
|
||||
else:
|
||||
old_count = None
|
||||
for ng in cluster.node_groups:
|
||||
if name == ng["name"]:
|
||||
old_count = ng["count"]
|
||||
break
|
||||
|
||||
if old_count != count:
|
||||
if "resize_node_groups" not in scale_object:
|
||||
scale_object["resize_node_groups"] = []
|
||||
|
||||
scale_object["resize_node_groups"].append(
|
||||
{"name": name,
|
||||
"count": int(count)}
|
||||
)
|
||||
try:
|
||||
sahara.clusters.scale(cluster_id, scale_object)
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
self.error_description = str(e)
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
|
@ -1,46 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard.utils import compatibility
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SaharaDashboard(horizon.Dashboard):
|
||||
name = _("Sahara")
|
||||
slug = "sahara"
|
||||
panels = ('clusters',
|
||||
'cluster_templates',
|
||||
'nodegroup_templates',
|
||||
'job_executions',
|
||||
'jobs',
|
||||
'job_binaries',
|
||||
'data_sources',
|
||||
'image_registry',
|
||||
'plugins')
|
||||
default_panel = 'clusters'
|
||||
nav = True
|
||||
supports_tenants = True
|
||||
|
||||
|
||||
horizon.register(SaharaDashboard)
|
||||
|
||||
LOG.info('Sahara recognizes Dashboard release as "%s"' %
|
||||
compatibility.get_dashboard_release())
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class DataSourcesPanel(horizon.Panel):
|
||||
name = _("Data Sources")
|
||||
slug = 'data_sources'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(DataSourcesPanel)
|
|
@ -1,60 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateDataSource(tables.LinkAction):
|
||||
name = "create data source"
|
||||
verbose_name = _("Create Data Source")
|
||||
url = "horizon:sahara:data_sources:create-data-source"
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
|
||||
class DeleteDataSource(tables.BatchAction):
|
||||
name = "delete"
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Data source")
|
||||
data_type_plural = _("Data sources")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.data_sources.delete(obj_id)
|
||||
|
||||
|
||||
class DataSourcesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:data_sources:details"))
|
||||
type = tables.Column("type",
|
||||
verbose_name=_("Type"))
|
||||
description = tables.Column("description",
|
||||
verbose_name=_("Description"))
|
||||
|
||||
class Meta:
|
||||
name = "data_sources"
|
||||
verbose_name = _("Data Sources")
|
||||
table_actions = (CreateDataSource,
|
||||
DeleteDataSource)
|
||||
row_actions = (DeleteDataSource,)
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "data_source_details_tab"
|
||||
template_name = ("data_sources/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
data_source_id = self.tab_group.kwargs['data_source_id']
|
||||
sahara = saharaclient(request)
|
||||
data_source = sahara.data_sources.get(data_source_id)
|
||||
return {"data_source": data_source}
|
||||
|
||||
|
||||
class DataSourceDetailsTabs(tabs.TabGroup):
|
||||
slug = "data_source_details"
|
||||
tabs = (GeneralTab,)
|
||||
sticky = True
|
|
@ -1,36 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
|
||||
import saharadashboard.data_sources.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.DataSourcesView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.DataSourcesView.as_view(),
|
||||
name='data-sources'),
|
||||
url(r'^create-data-source$',
|
||||
views.CreateDataSourceView.as_view(),
|
||||
name='create-data-source'),
|
||||
url(r'^(?P<data_source_id>[^/]+)$',
|
||||
views.DataSourceDetailsView.as_view(),
|
||||
name='details'))
|
|
@ -1,58 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.data_sources.tables import DataSourcesTable
|
||||
import saharadashboard.data_sources.tabs as _tabs
|
||||
import saharadashboard.data_sources.workflows.create as create_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DataSourcesView(tables.DataTableView):
|
||||
table_class = DataSourcesTable
|
||||
template_name = 'data_sources/data_sources.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
data_sources = sahara.data_sources.list()
|
||||
return data_sources
|
||||
|
||||
|
||||
class CreateDataSourceView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.CreateDataSource
|
||||
success_url = \
|
||||
"horizon:sahara:data-sources:create-data-source"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "data_sources/create.html"
|
||||
|
||||
|
||||
class DataSourceDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.DataSourceDetailsTabs
|
||||
template_name = 'data_sources/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DataSourceDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
|
@ -1,109 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralConfigAction(workflows.Action):
|
||||
data_source_name = forms.CharField(label=_("Name"),
|
||||
required=True)
|
||||
|
||||
data_source_type = forms.ChoiceField(
|
||||
label=_("Data Source Type"),
|
||||
required=True,
|
||||
choices=[("swift", "Swift"), ("hdfs", "HDFS")],
|
||||
widget=forms.Select(attrs={"class": "data_source_type_choice"}))
|
||||
|
||||
data_source_url = forms.CharField(label=_("URL"),
|
||||
required=True)
|
||||
|
||||
data_source_credential_user = forms.CharField(label=_("Source username"),
|
||||
required=True)
|
||||
|
||||
data_source_credential_pass = forms.CharField(
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
||||
label=_("Source password"),
|
||||
required=True)
|
||||
|
||||
data_source_description = forms.CharField(
|
||||
label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(workflows.Action, self).clean()
|
||||
ds_type = cleaned_data.get("data_source_type", "")
|
||||
|
||||
if ds_type == "hdfs":
|
||||
if "data_source_credential_user" in self._errors:
|
||||
del self._errors["data_source_credential_user"]
|
||||
if "data_source_credential_pass" in self._errors:
|
||||
del self._errors["data_source_credential_pass"]
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
name = _("Create Data Source")
|
||||
help_text_template = \
|
||||
("data_sources/_create_data_source_help.html")
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context["general_" + k] = v
|
||||
|
||||
context["source_url"] = context["general_data_source_url"]
|
||||
|
||||
if context["general_data_source_type"] == "swift":
|
||||
if not context["general_data_source_url"].startswith("swift://"):
|
||||
context["source_url"] = "%s://%s" % \
|
||||
("swift",
|
||||
context["general_data_source_url"])
|
||||
return context
|
||||
|
||||
|
||||
class CreateDataSource(workflows.Workflow):
|
||||
slug = "create_data_source"
|
||||
name = _("Create Data Source")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Data source created")
|
||||
failure_message = _("Could not create data source")
|
||||
success_url = "horizon:sahara:data_sources:index"
|
||||
default_steps = (GeneralConfig, )
|
||||
|
||||
def handle(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
sahara.data_sources.create(
|
||||
context["general_data_source_name"],
|
||||
context["general_data_source_description"],
|
||||
context["general_data_source_type"],
|
||||
context["source_url"],
|
||||
context.get("general_data_source_credential_user", None),
|
||||
context.get("general_data_source_credential_pass", None))
|
||||
return True
|
|
@ -1,127 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import json
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
# horizon.api is for backward compatibility with folsom
|
||||
glance = importutils.import_any('openstack_dashboard.api.glance',
|
||||
'horizon.api.glance')
|
||||
|
||||
|
||||
class ImageForm(forms.SelfHandlingForm):
|
||||
image_id = forms.CharField(widget=forms.HiddenInput())
|
||||
tags_list = forms.CharField(widget=forms.HiddenInput())
|
||||
user_name = forms.CharField(max_length=80, label=_("User Name"))
|
||||
description = forms.CharField(max_length=80,
|
||||
label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea(attrs={'cols': 80,
|
||||
'rows': 20}))
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
sahara = saharaclient.client(request)
|
||||
|
||||
image_id = data['image_id']
|
||||
user_name = data['user_name']
|
||||
desc = data['description']
|
||||
sahara.images.update_image(image_id, user_name, desc)
|
||||
|
||||
image_tags = json.loads(data["tags_list"])
|
||||
sahara.images.update_tags(image_id, image_tags)
|
||||
|
||||
messages.success(request, self.message)
|
||||
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
messages.error(request, str(e))
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
|
||||
|
||||
class EditTagsForm(ImageForm):
|
||||
message = _("Image updated.")
|
||||
image_id = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
|
||||
class RegisterImageForm(ImageForm):
|
||||
message = _("Image registered.")
|
||||
image_id = forms.ChoiceField(label=_("Image"),
|
||||
required=True)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(RegisterImageForm, self).__init__(request, *args, **kwargs)
|
||||
self._populate_image_id_choices()
|
||||
|
||||
def _populate_image_id_choices(self):
|
||||
images = self._get_available_images(self.request)
|
||||
choices = [(image.id, image.name)
|
||||
for image in images
|
||||
if image.properties.get("image_type", '') != "snapshot"]
|
||||
if choices:
|
||||
choices.insert(0, ("", _("Select Image")))
|
||||
else:
|
||||
choices.insert(0, ("", _("No images available.")))
|
||||
self.fields['image_id'].choices = choices
|
||||
|
||||
def _get_images(self, request, filter):
|
||||
try:
|
||||
images, _more, _prev = glance.image_list_detailed(
|
||||
request, filters=filter)
|
||||
except Exception:
|
||||
images = []
|
||||
exceptions.handle(request,
|
||||
_("Unable to retrieve images with filter %s.") %
|
||||
filter)
|
||||
return images
|
||||
|
||||
def _get_public_images(self, request):
|
||||
filter = {"is_public": True,
|
||||
"status": "active"}
|
||||
return self._get_images(request, filter)
|
||||
|
||||
def _get_tenant_images(self, request):
|
||||
filter = {"owner": request.user.tenant_id,
|
||||
"status": "active"}
|
||||
return self._get_images(request, filter)
|
||||
|
||||
def _get_available_images(self, request):
|
||||
|
||||
images = self._get_tenant_images(request)
|
||||
if request.user.is_superuser:
|
||||
images += self._get_public_images(request)
|
||||
|
||||
final_images = []
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
image_ids = [img.id for img in sahara.images.list()]
|
||||
|
||||
for image in images:
|
||||
if image.id not in image_ids:
|
||||
image_ids.append(image.id)
|
||||
final_images.append(image)
|
||||
return [image for image in final_images
|
||||
if image.container_format
|
||||
not in ('aki', 'ari')]
|
|
@ -1,27 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class ImageRegistryPanel(horizon.Panel):
|
||||
name = _("Image Registry")
|
||||
slug = 'image_registry'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(ImageRegistryPanel)
|
|
@ -1,75 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django import template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.utils import compatibility
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EditTagsAction(tables.LinkAction):
|
||||
name = "edit_tags"
|
||||
verbose_name = _("Edit Tags")
|
||||
url = "horizon:sahara:image_registry:edit_tags"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
|
||||
def tags_to_string(image):
|
||||
template_name = 'image_registry/_list_tags.html'
|
||||
context = {"image": image}
|
||||
return template.loader.render_to_string(template_name, context)
|
||||
|
||||
|
||||
class RegisterImage(tables.LinkAction):
|
||||
name = "register"
|
||||
verbose_name = _("Register Image")
|
||||
url = "horizon:sahara:image_registry:register"
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
|
||||
class UnregisterImages(tables.BatchAction):
|
||||
name = "Unregister"
|
||||
action_present = _("Unregister")
|
||||
action_past = _("Unregistered")
|
||||
data_type_singular = _("Image")
|
||||
data_type_plural = _("Images")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.images.unregister_image(obj_id)
|
||||
|
||||
|
||||
class ImageRegistryTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Image"),
|
||||
link=compatibility.convert_url(
|
||||
"horizon:project:"
|
||||
"images:images:detail"))
|
||||
tags = tables.Column(tags_to_string,
|
||||
verbose_name=_("Tags"))
|
||||
|
||||
class Meta:
|
||||
name = "image_registry"
|
||||
verbose_name = _("Image Registry")
|
||||
table_actions = ()
|
||||
table_actions = (RegisterImage, UnregisterImages,)
|
||||
row_actions = (EditTagsAction, UnregisterImages,)
|
|
@ -1,39 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
from saharadashboard.image_registry.views import EditTagsView
|
||||
from saharadashboard.image_registry.views import ImageRegistryView
|
||||
from saharadashboard.image_registry.views import RegisterImageView
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', ImageRegistryView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', ImageRegistryView.as_view(),
|
||||
name='image_registry'),
|
||||
url(r'^edit_tags/(?P<image_id>[^/]+)/$',
|
||||
EditTagsView.as_view(),
|
||||
name='edit_tags'),
|
||||
url(r'^register/$',
|
||||
RegisterImageView.as_view(),
|
||||
name='register'),
|
||||
)
|
|
@ -1,98 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.image_registry.forms import EditTagsForm
|
||||
from saharadashboard.image_registry.forms import RegisterImageForm
|
||||
from saharadashboard.image_registry.tables import ImageRegistryTable
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ImageRegistryView(tables.DataTableView):
|
||||
table_class = ImageRegistryTable
|
||||
template_name = 'image_registry/image_registry.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
|
||||
return sahara.images.list()
|
||||
|
||||
|
||||
def update_context_with_plugin_tags(request, context):
|
||||
sahara = saharaclient(request)
|
||||
plugins = sahara.plugins.list()
|
||||
|
||||
plugins_object = dict()
|
||||
for plugin in plugins:
|
||||
plugins_object[plugin.name] = dict()
|
||||
for version in plugin.versions:
|
||||
plugins_object[plugin.name][version] = []
|
||||
details = sahara.plugins.get_version_details(plugin.name,
|
||||
version)
|
||||
|
||||
for tag in details.required_image_tags:
|
||||
plugins_object[plugin.name][version].append(tag)
|
||||
|
||||
context["plugins"] = plugins_object
|
||||
return context
|
||||
|
||||
|
||||
class EditTagsView(forms.ModalFormView):
|
||||
form_class = EditTagsForm
|
||||
template_name = 'image_registry/edit_tags.html'
|
||||
success_url = reverse_lazy('horizon:sahara:image_registry:index')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EditTagsView, self).get_context_data(**kwargs)
|
||||
context['image'] = self.get_object()
|
||||
context = update_context_with_plugin_tags(self.request, context)
|
||||
return context
|
||||
|
||||
def get_object(self):
|
||||
sahara = saharaclient(self.request)
|
||||
return sahara.images.get(self.kwargs["image_id"])
|
||||
|
||||
def get_initial(self):
|
||||
image = self.get_object()
|
||||
|
||||
return {"image_id": image.id,
|
||||
"tags_list": json.dumps(image.tags),
|
||||
"user_name": image.username,
|
||||
"description": image.description}
|
||||
|
||||
|
||||
class RegisterImageView(forms.ModalFormView):
|
||||
form_class = RegisterImageForm
|
||||
template_name = 'image_registry/register_image.html'
|
||||
success_url = reverse_lazy('horizon:sahara:image_registry:index')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(RegisterImageView, self).get_context_data(**kwargs)
|
||||
context = update_context_with_plugin_tags(self.request, context)
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
# need this initialization to allow registration
|
||||
# of images without tags
|
||||
return {"tags_list": json.dumps([])}
|
|
@ -1,183 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from django.forms.util import flatatt
|
||||
from django.forms import widgets
|
||||
from django import template
|
||||
from django.template.defaultfilters import linebreaks
|
||||
from django.template.defaultfilters import safe
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LabeledInput(widgets.Input):
|
||||
def render(self, name, values, attrs=None):
|
||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||
output = "<span id='%s'>%s</span>%s" %\
|
||||
("id_%s_label" % name,
|
||||
"internal-db://",
|
||||
('<input%s />' % flatatt(final_attrs)))
|
||||
return mark_safe(output)
|
||||
|
||||
|
||||
class JobBinaryCreateForm(forms.SelfHandlingForm):
|
||||
NEW_SCRIPT = "%%%NEWSCRIPT%%%"
|
||||
UPLOAD_BIN = "%%%UPLOADFILE%%%"
|
||||
|
||||
job_binary_name = forms.CharField(label=_("Name"),
|
||||
required=True)
|
||||
|
||||
job_binary_type = forms.ChoiceField(label=_("Storage type"),
|
||||
required=True)
|
||||
|
||||
job_binary_url = forms.CharField(label=_("URL"),
|
||||
required=False,
|
||||
widget=LabeledInput())
|
||||
job_binary_internal = forms.ChoiceField(label=_("Internal binary"),
|
||||
required=False)
|
||||
|
||||
job_binary_file = forms.FileField(label=_("Upload File"),
|
||||
required=False)
|
||||
|
||||
job_binary_script_name = forms.CharField(label=_("Script name"),
|
||||
required=False)
|
||||
|
||||
job_binary_script = forms.CharField(label=_("Script text"),
|
||||
required=False,
|
||||
widget=forms.Textarea())
|
||||
|
||||
job_binary_username = forms.CharField(label=_("Username"),
|
||||
required=False)
|
||||
|
||||
job_binary_password = forms.CharField(label=_("Password"),
|
||||
required=False,
|
||||
widget=forms.PasswordInput(
|
||||
attrs={'autocomplete': 'off'}))
|
||||
|
||||
job_binary_description = forms.CharField(label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea())
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(JobBinaryCreateForm, self).__init__(request, *args, **kwargs)
|
||||
|
||||
self.help_text_template = "job_binaries/_create_job_binary_help.html"
|
||||
|
||||
self.fields["job_binary_type"].choices =\
|
||||
[("internal-db", "Internal database"),
|
||||
("swift", "Swift")]
|
||||
|
||||
self.fields["job_binary_internal"].choices =\
|
||||
self.populate_job_binary_internal_choices(request)
|
||||
|
||||
def populate_job_binary_internal_choices(self, request):
|
||||
sahara = saharaclient.client(request)
|
||||
job_binaries = sahara.job_binary_internals.list()
|
||||
|
||||
choices = [(job_binary.id, job_binary.name)
|
||||
for job_binary in job_binaries]
|
||||
choices.insert(0, (self.NEW_SCRIPT, '*Create a script'))
|
||||
choices.insert(0, (self.UPLOAD_BIN, '*Upload a new file'))
|
||||
|
||||
return choices
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
sahara = saharaclient.client(request)
|
||||
extra = {}
|
||||
bin_url = "%s://%s" % (context["job_binary_type"],
|
||||
context["job_binary_url"])
|
||||
if(context["job_binary_type"] == "internal-db"):
|
||||
bin_url = self.handle_internal(request, context)
|
||||
elif(context["job_binary_type"] == "swift"):
|
||||
extra = self.handle_swift(request, context)
|
||||
|
||||
sahara.job_binaries.create(
|
||||
context["job_binary_name"],
|
||||
bin_url,
|
||||
context["job_binary_description"],
|
||||
extra)
|
||||
messages.success(request, "Successfully created job binary")
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
messages.error(request, str(e))
|
||||
return False
|
||||
except Exception as e:
|
||||
messages.error(request, str(e))
|
||||
return False
|
||||
|
||||
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 += linebreaks(force_unicode(self.help_text))
|
||||
return safe(text)
|
||||
|
||||
class Meta:
|
||||
name = _("Create Job Binary")
|
||||
help_text_template = \
|
||||
("job_binaries/_create_job_binary_help.html")
|
||||
|
||||
def handle_internal(self, request, context):
|
||||
result = ""
|
||||
sahara = saharaclient.client(request)
|
||||
|
||||
bin_id = context["job_binary_internal"]
|
||||
if(bin_id == self.UPLOAD_BIN):
|
||||
result = sahara.job_binary_internals.create(
|
||||
self.get_unique_binary_name(
|
||||
request, request.FILES["job_binary_file"].name),
|
||||
request.FILES["job_binary_file"].read())
|
||||
elif(bin_id == self.NEW_SCRIPT):
|
||||
result = sahara.job_binary_internals.create(
|
||||
self.get_unique_binary_name(
|
||||
request, context["job_binary_script_name"]),
|
||||
context["job_binary_script"])
|
||||
|
||||
bin_id = result.id
|
||||
return "internal-db://%s" % bin_id
|
||||
|
||||
def handle_swift(self, request, context):
|
||||
username = context["job_binary_username"]
|
||||
password = context["job_binary_password"]
|
||||
|
||||
extra = {
|
||||
"user": username,
|
||||
"password": password
|
||||
}
|
||||
return extra
|
||||
|
||||
def get_unique_binary_name(self, request, base_name):
|
||||
sahara = saharaclient.client(request)
|
||||
internals = sahara.job_binary_internals.list()
|
||||
names = [internal.name for internal in internals]
|
||||
if base_name in names:
|
||||
return "%s_%s" % (base_name, uuid.uuid1())
|
||||
return base_name
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class JobBinariesPanel(horizon.Panel):
|
||||
name = _("Job Binaries")
|
||||
slug = 'job_binaries'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(JobBinariesPanel)
|
|
@ -1,79 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateJobBinary(tables.LinkAction):
|
||||
name = "create job binary"
|
||||
verbose_name = _("Create Job Binary")
|
||||
url = "horizon:sahara:job_binaries:create-job-binary"
|
||||
classes = ("btn-launch", "ajax-modal")
|
||||
|
||||
|
||||
class DeleteJobBinary(tables.BatchAction):
|
||||
name = "delete"
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Job binary")
|
||||
data_type_plural = _("Job binaries")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient.client(request)
|
||||
jb = sahara.job_binaries.get(obj_id)
|
||||
(jb_type, jb_internal_id) = jb.url.split("://")
|
||||
if jb_type == "internal-db":
|
||||
try:
|
||||
sahara.job_binary_internals.delete(jb_internal_id)
|
||||
except api_base.APIException:
|
||||
# nothing to do for job-binary-internal if
|
||||
# it does not exist.
|
||||
pass
|
||||
|
||||
sahara.job_binaries.delete(obj_id)
|
||||
|
||||
|
||||
class DownloadJobBinary(tables.LinkAction):
|
||||
name = "download job binary"
|
||||
verbose_name = _("Download Job Binary")
|
||||
url = "horizon:sahara:job_binaries:download"
|
||||
classes = ("btn-edit")
|
||||
|
||||
|
||||
class JobBinariesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:job_binaries:details"))
|
||||
type = tables.Column("url",
|
||||
verbose_name=_("Url"))
|
||||
description = tables.Column("description",
|
||||
verbose_name=_("Description"))
|
||||
|
||||
class Meta:
|
||||
name = "job_binaries"
|
||||
verbose_name = _("Job Binaries")
|
||||
table_actions = (CreateJobBinary,
|
||||
DeleteJobBinary)
|
||||
row_actions = (DeleteJobBinary, DownloadJobBinary)
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "job_binaries_details_tab"
|
||||
template_name = ("job_binaries/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
job_binary_id = self.tab_group.kwargs['job_binary_id']
|
||||
sahara = saharaclient(request)
|
||||
job_binary = sahara.job_binaries.get(job_binary_id)
|
||||
return {"job_binary": job_binary}
|
||||
|
||||
|
||||
class JobBinaryDetailsTabs(tabs.TabGroup):
|
||||
slug = "job_binary_details"
|
||||
tabs = (GeneralTab,)
|
||||
sticky = True
|
|
@ -1,39 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
|
||||
import saharadashboard.job_binaries.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.JobBinariesView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.JobBinariesView.as_view(),
|
||||
name='job-binaries'),
|
||||
url(r'^create-job-binary$',
|
||||
views.CreateJobBinaryView.as_view(),
|
||||
name='create-job-binary'),
|
||||
url(r'^(?P<job_binary_id>[^/]+)$',
|
||||
views.JobBinaryDetailsView.as_view(),
|
||||
name='details'),
|
||||
url(r'^(?P<job_binary_id>[^/]+)/download/$',
|
||||
views.DownloadJobBinaryView.as_view(),
|
||||
name='download'))
|
|
@ -1,85 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django import http
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import View
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.job_binaries.forms as job_binary_forms
|
||||
from saharadashboard.job_binaries.tables import JobBinariesTable
|
||||
import saharadashboard.job_binaries.tabs as _tabs
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobBinariesView(tables.DataTableView):
|
||||
table_class = JobBinariesTable
|
||||
template_name = 'job_binaries/job_binaries.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
job_binaries = sahara.job_binaries.list()
|
||||
return job_binaries
|
||||
|
||||
|
||||
class CreateJobBinaryView(forms.ModalFormView):
|
||||
form_class = job_binary_forms.JobBinaryCreateForm
|
||||
success_url = reverse_lazy('horizon:sahara:job_binaries:index')
|
||||
classes = ("ajax-modal")
|
||||
template_name = "job_binaries/create.html"
|
||||
|
||||
|
||||
class JobBinaryDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.JobBinaryDetailsTabs
|
||||
template_name = 'job_binaries/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(JobBinaryDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
class DownloadJobBinaryView(View):
|
||||
def get(self, request, job_binary_id=None):
|
||||
try:
|
||||
sahara = saharaclient(request)
|
||||
jb = sahara.job_binaries.get(job_binary_id)
|
||||
data = sahara.job_binaries.get_file(job_binary_id)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:sahara:job_binaries:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to fetch job binary: %(exc)s'),
|
||||
redirect=redirect)
|
||||
|
||||
response = http.HttpResponse(mimetype='application/binary')
|
||||
response['Content-Disposition'] = \
|
||||
'attachment; filename=%s' % slugify(jb.name)
|
||||
response.write(data)
|
||||
response['Content-Length'] = str(len(data))
|
||||
return response
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class JobExecutionsPanel(horizon.Panel):
|
||||
name = _("Job Executions")
|
||||
slug = 'job_executions'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(JobExecutionsPanel)
|
|
@ -1,113 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.core import urlresolvers
|
||||
from django.utils import http
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.jobs import tables as j_t
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeleteJobExecution(tables.BatchAction):
|
||||
name = "delete"
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Job execution")
|
||||
data_type_plural = _("Job executions")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.job_executions.delete(obj_id)
|
||||
|
||||
|
||||
class ReLaunchJobExistingCluster(j_t.ChoosePlugin):
|
||||
name = "relaunch-job-existing"
|
||||
verbose_name = _("Relaunch On Existing Cluster")
|
||||
action_present = _("Launch")
|
||||
action_past = _("Launched")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
url = "horizon:sahara:jobs:launch-job"
|
||||
classes = ('ajax-modal', 'btn-launch')
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = urlresolvers.reverse(self.url)
|
||||
|
||||
params = http.urlencode({'job_id': datum.job_id,
|
||||
'job_execution_id': datum.id})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
|
||||
class ReLaunchJobNewCluster(ReLaunchJobExistingCluster):
|
||||
name = "relaunch-job-new"
|
||||
verbose_name = _("Relaunch On New Cluster")
|
||||
action_present = _("Launch")
|
||||
action_past = _("Launched")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
url = "horizon:sahara:jobs:choose-plugin"
|
||||
classes = ('ajax-modal', 'btn-launch')
|
||||
|
||||
|
||||
class UpdateRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, job_execution_id):
|
||||
sahara = saharaclient(request)
|
||||
job_execution = sahara.job_executions.get(job_execution_id)
|
||||
return job_execution
|
||||
|
||||
|
||||
class JobExecutionsTable(tables.DataTable):
|
||||
class StatusColumn(tables.Column):
|
||||
def get_raw_data(self, datum):
|
||||
return datum.info['status']
|
||||
|
||||
STATUS_CHOICES = (
|
||||
("DONEWITHERROR", False),
|
||||
("FAILED", False),
|
||||
("KILLED", False),
|
||||
("SUCCEEDED", True),
|
||||
)
|
||||
|
||||
name = tables.Column("id",
|
||||
verbose_name=_("ID"),
|
||||
display_choices=(("id", "ID"), ("name", "Name")),
|
||||
link=("horizon:sahara:job_executions:details"))
|
||||
|
||||
status = StatusColumn("info",
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES,
|
||||
verbose_name=_("Status"))
|
||||
|
||||
def get_object_display(self, datum):
|
||||
return datum.id
|
||||
|
||||
class Meta:
|
||||
name = "job_executions"
|
||||
row_class = UpdateRow
|
||||
status_columns = ["status"]
|
||||
verbose_name = _("Job Executions")
|
||||
table_actions = [DeleteJobExecution]
|
||||
row_actions = [DeleteJobExecution,
|
||||
ReLaunchJobExistingCluster,
|
||||
ReLaunchJobNewCluster]
|
|
@ -1,73 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "job_execution_tab"
|
||||
template_name = ("job_executions/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
job_execution_id = self.tab_group.kwargs['job_execution_id']
|
||||
sahara = saharaclient(request)
|
||||
job_execution = sahara.job_executions.get(job_execution_id)
|
||||
object_names = self.get_object_names(job_execution, sahara)
|
||||
|
||||
return {"job_execution": job_execution,
|
||||
"object_names": object_names}
|
||||
|
||||
def get_object_names(self, job_ex, s_client):
|
||||
object_names = {}
|
||||
obj_names_map = {'input_name': {'obj': 'data_sources',
|
||||
'obj_id': job_ex.input_id},
|
||||
'output_name': {'obj': 'data_sources',
|
||||
'obj_id': job_ex.output_id},
|
||||
'cluster_name': {'obj': 'clusters',
|
||||
'obj_id': job_ex.cluster_id},
|
||||
'job_name': {'obj': 'jobs',
|
||||
'obj_id': job_ex.job_id}}
|
||||
for item in obj_names_map:
|
||||
object_names[item] = (
|
||||
self.get_object_name(obj_names_map[item]['obj_id'],
|
||||
obj_names_map[item]['obj'],
|
||||
s_client))
|
||||
|
||||
return object_names
|
||||
|
||||
def get_object_name(self, obj_id, sahara_obj, s_client):
|
||||
object_name = None
|
||||
try:
|
||||
s_obj = getattr(s_client, sahara_obj)
|
||||
obj = s_obj.get(obj_id)
|
||||
object_name = obj.name
|
||||
except Exception as e:
|
||||
LOG.warn("Unable to get name for %s with object_id %s (%s)" %
|
||||
(sahara_obj, obj_id, str(e)))
|
||||
return object_name
|
||||
|
||||
|
||||
class JobExecutionDetailsTabs(tabs.TabGroup):
|
||||
slug = "job_execution_details"
|
||||
tabs = (GeneralTab,)
|
||||
sticky = True
|
|
@ -1,38 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
|
||||
import saharadashboard.job_executions.views as views
|
||||
from saharadashboard.jobs import views as job_views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.JobExecutionsView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.JobExecutionsView.as_view(),
|
||||
name='job-executions'),
|
||||
url(r'^launch-job$',
|
||||
job_views.LaunchJobView.as_view()),
|
||||
url(r'^launch-job-new-cluster$',
|
||||
job_views.LaunchJobNewClusterView.as_view()),
|
||||
url(r'^(?P<job_execution_id>[^/]+)$',
|
||||
views.JobExecutionDetailsView.as_view(),
|
||||
name='details'))
|
|
@ -1,48 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.job_executions.tables import JobExecutionsTable
|
||||
import saharadashboard.job_executions.tabs as _tabs
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobExecutionsView(tables.DataTableView):
|
||||
table_class = JobExecutionsTable
|
||||
template_name = 'job_executions/job_executions.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
jobs = sahara.job_executions.list()
|
||||
return jobs
|
||||
|
||||
|
||||
class JobExecutionDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.JobExecutionDetailsTabs
|
||||
template_name = 'job_executions/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(JobExecutionDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class JobsPanel(horizon.Panel):
|
||||
name = _("Jobs")
|
||||
slug = 'jobs'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(JobsPanel)
|
|
@ -1,111 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.core import urlresolvers
|
||||
from django.utils import http
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateJob(tables.LinkAction):
|
||||
name = "create job"
|
||||
verbose_name = _("Create Job")
|
||||
url = "horizon:sahara:jobs:create-job"
|
||||
classes = ("btn-launch", "ajax-modal", "create_job_class")
|
||||
|
||||
|
||||
class DeleteJob(tables.BatchAction):
|
||||
name = "delete"
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
classes = ('btn-danger', 'btn-terminate')
|
||||
|
||||
def action(self, request, obj_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.jobs.delete(obj_id)
|
||||
|
||||
|
||||
class LaunchJobExistingCluster(tables.LinkAction):
|
||||
name = "launch-job-existing"
|
||||
verbose_name = _("Launch On Existing Cluster")
|
||||
action_present = _("Launch")
|
||||
action_past = _("Launched")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
url = "horizon:sahara:jobs:launch-job"
|
||||
classes = ('ajax-modal', 'btn-launch')
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = urlresolvers.reverse(self.url)
|
||||
|
||||
params = http.urlencode({"job_id": datum.id})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
|
||||
class LaunchJobNewCluster(tables.LinkAction):
|
||||
name = "launch-job-new"
|
||||
verbose_name = _("Launch On New Cluster")
|
||||
action_present = _("Launch")
|
||||
action_past = _("Launched")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
url = "horizon:sahara:jobs:launch-job-new-cluster"
|
||||
classes = ('ajax-modal', 'btn-launch')
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = urlresolvers.reverse(self.url)
|
||||
|
||||
params = http.urlencode({"job_id": datum.id})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
|
||||
class ChoosePlugin(tables.LinkAction):
|
||||
name = "launch-job-new"
|
||||
verbose_name = _("Launch On New Cluster")
|
||||
action_present = _("Launch")
|
||||
action_past = _("Launched")
|
||||
data_type_singular = _("Job")
|
||||
data_type_plural = _("Jobs")
|
||||
url = "horizon:sahara:jobs:choose-plugin"
|
||||
classes = ('ajax-modal', 'btn-launch')
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = urlresolvers.reverse(self.url)
|
||||
|
||||
params = http.urlencode({"job_id": datum.id})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
|
||||
class JobsTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:jobs:details"))
|
||||
description = tables.Column("description",
|
||||
verbose_name=_("Description"))
|
||||
|
||||
class Meta:
|
||||
name = "jobs"
|
||||
verbose_name = _("Jobs")
|
||||
table_actions = (CreateJob,
|
||||
DeleteJob)
|
||||
row_actions = (ChoosePlugin, LaunchJobExistingCluster, DeleteJob,)
|
|
@ -1,41 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "job_details_tab"
|
||||
template_name = ("jobs/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
job_id = self.tab_group.kwargs['job_id']
|
||||
sahara = saharaclient(request)
|
||||
job = sahara.jobs.get(job_id)
|
||||
return {"job": job}
|
||||
|
||||
|
||||
class JobDetailsTabs(tabs.TabGroup):
|
||||
slug = "job_details"
|
||||
tabs = (GeneralTab,)
|
||||
sticky = True
|
|
@ -1,45 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
|
||||
import saharadashboard.jobs.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', views.JobsView.as_view(),
|
||||
name='index'),
|
||||
url(r'^$', views.JobsView.as_view(),
|
||||
name='jobs'),
|
||||
url(r'^create-job$',
|
||||
views.CreateJobView.as_view(),
|
||||
name='create-job'),
|
||||
url(r'^launch-job$',
|
||||
views.LaunchJobView.as_view(),
|
||||
name='launch-job'),
|
||||
url(r'^launch-job-new-cluster$',
|
||||
views.LaunchJobNewClusterView.as_view(),
|
||||
name='launch-job-new-cluster'),
|
||||
url(r'^choose-plugin$',
|
||||
views.ChoosePluginView.as_view(),
|
||||
name='choose-plugin'),
|
||||
url(r'^(?P<job_id>[^/]+)$',
|
||||
views.JobDetailsView.as_view(),
|
||||
name='details'))
|
|
@ -1,103 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.http import HttpResponse
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.jobs.tables as _tables
|
||||
import saharadashboard.jobs.tabs as _tabs
|
||||
import saharadashboard.jobs.workflows.create as create_flow
|
||||
import saharadashboard.jobs.workflows.launch as launch_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobsView(tables.DataTableView):
|
||||
table_class = _tables.JobsTable
|
||||
template_name = 'jobs/jobs.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
jobs = sahara.jobs.list()
|
||||
return jobs
|
||||
|
||||
|
||||
class CreateJobView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.CreateJob
|
||||
success_url = "horizon:sahara:jobs:create-job"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "jobs/create.html"
|
||||
|
||||
|
||||
class JobDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.JobDetailsTabs
|
||||
template_name = 'jobs/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(JobDetailsView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
class LaunchJobView(workflows.WorkflowView):
|
||||
workflow_class = launch_flow.LaunchJob
|
||||
success_url = "horizon:sahara:jobs"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "jobs/launch.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.is_ajax():
|
||||
if request.REQUEST.get("json", None):
|
||||
job_id = request.REQUEST.get("job_id")
|
||||
sahara = saharaclient(request)
|
||||
job_type = sahara.jobs.get(job_id).type
|
||||
return HttpResponse(json.dumps({"job_type": job_type}),
|
||||
mimetype='application/json')
|
||||
return super(LaunchJobView, self).get(request, args, kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(LaunchJobView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
|
||||
class LaunchJobNewClusterView(workflows.WorkflowView):
|
||||
workflow_class = launch_flow.LaunchJobNewCluster
|
||||
success_url = "horizon:sahara:jobs"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "jobs/launch.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(LaunchJobNewClusterView, self).\
|
||||
get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
|
||||
class ChoosePluginView(workflows.WorkflowView):
|
||||
workflow_class = launch_flow.ChosePluginVersion
|
||||
success_url = "horizon:sahara:jobs"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "jobs/launch.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ChoosePluginView, self).get_context_data(**kwargs)
|
||||
return context
|
|
@ -1,144 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AdditionalLibsAction(workflows.Action):
|
||||
|
||||
lib_binaries = forms.ChoiceField(label=_("Choose libraries"),
|
||||
required=False)
|
||||
|
||||
lib_ids = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
def populate_lib_binaries_choices(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
job_binaries = sahara.job_binaries.list()
|
||||
|
||||
choices = [(job_binary.id, job_binary.name)
|
||||
for job_binary in job_binaries]
|
||||
choices.insert(0, ('', '-- not selected --'))
|
||||
|
||||
return choices
|
||||
|
||||
class Meta:
|
||||
name = _("Libs")
|
||||
help_text_template = "jobs/_create_job_libs_help.html"
|
||||
|
||||
|
||||
class GeneralConfigAction(workflows.Action):
|
||||
|
||||
job_name = forms.CharField(label=_("Name"),
|
||||
required=True)
|
||||
|
||||
job_type = forms.ChoiceField(label=_("Job Type"),
|
||||
required=True)
|
||||
|
||||
main_binary = forms.ChoiceField(label=_("Choose a main binary"),
|
||||
required=False,
|
||||
help_text=_("Choose the binary which "
|
||||
"should be used in this "
|
||||
"Job."))
|
||||
|
||||
job_description = forms.CharField(label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
def populate_job_type_choices(self, request, context):
|
||||
choices = [("Pig", "Pig"), ("Hive", "Hive"),
|
||||
("MapReduce", "MapReduce"),
|
||||
("MapReduce.Streaming", "Streaming MapReduce"),
|
||||
("Java", "Java Action")]
|
||||
return choices
|
||||
|
||||
def populate_main_binary_choices(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
job_binaries = sahara.job_binaries.list()
|
||||
|
||||
choices = [(job_binary.id, job_binary.name)
|
||||
for job_binary in job_binaries]
|
||||
choices.insert(0, ('', '-- not selected --'))
|
||||
return choices
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(workflows.Action, self).clean()
|
||||
job_type = cleaned_data.get("job_type", "")
|
||||
|
||||
if job_type in ["Java", "MapReduce"]:
|
||||
cleaned_data['main_binary'] = None
|
||||
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
name = _("Create Job")
|
||||
help_text_template = "jobs/_create_job_help.html"
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
contributes = ("job_name", "job_type", "job_description", "main_binary")
|
||||
|
||||
|
||||
class ConfigureLibs(workflows.Step):
|
||||
action_class = AdditionalLibsAction
|
||||
template_name = "jobs/library_template.html"
|
||||
|
||||
def contribute(self, data, context):
|
||||
chosen_libs = json.loads(data.get("lib_ids", '[]'))
|
||||
for k in xrange(len(chosen_libs)):
|
||||
context["lib_" + str(k)] = chosen_libs[k]
|
||||
return context
|
||||
|
||||
|
||||
class CreateJob(workflows.Workflow):
|
||||
slug = "create_job"
|
||||
name = _("Create Job")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Job created")
|
||||
failure_message = _("Could not create job")
|
||||
success_url = "horizon:sahara:jobs:index"
|
||||
default_steps = (GeneralConfig, ConfigureLibs)
|
||||
|
||||
def handle(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
main_locations = []
|
||||
lib_locations = []
|
||||
|
||||
for k in context.keys():
|
||||
if k.startswith('lib_'):
|
||||
lib_locations.append(context.get(k))
|
||||
|
||||
if context.get("main_binary", None):
|
||||
main_locations.append(context["main_binary"])
|
||||
|
||||
sahara.jobs.create(
|
||||
context["job_name"],
|
||||
context["job_type"],
|
||||
main_locations,
|
||||
lib_locations,
|
||||
context["job_description"])
|
||||
return True
|
|
@ -1,443 +0,0 @@
|
|||
# Copyright (c) 2013 Red Hat 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.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.cluster_templates.workflows.create as t_flows
|
||||
import saharadashboard.clusters.workflows.create as c_flow
|
||||
import saharadashboard.utils.workflow_helpers as whelpers
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JobExecutionGeneralConfigAction(workflows.Action):
|
||||
job_input = forms.ChoiceField(
|
||||
label=_("Input"),
|
||||
required=True,
|
||||
initial=(None, "None"),
|
||||
widget=forms.Select(attrs={"class": "job_input_choice"}))
|
||||
|
||||
job_output = forms.ChoiceField(
|
||||
label=_("Output"),
|
||||
required=True,
|
||||
initial=(None, "None"),
|
||||
widget=forms.Select(attrs={"class": "job_output_choice"}))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(JobExecutionGeneralConfigAction, self).__init__(request,
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
if request.REQUEST.get("job_id", None) is None:
|
||||
self.fields["job"] = forms.ChoiceField(
|
||||
label=_("Job"),
|
||||
required=True)
|
||||
self.fields["job"].choices = self.populate_job_choices(request)
|
||||
else:
|
||||
self.fields["job"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=request.REQUEST.get("job_id", None))
|
||||
|
||||
def populate_job_input_choices(self, request, context):
|
||||
return self.get_data_source_choices(request, context)
|
||||
|
||||
def populate_job_output_choices(self, request, context):
|
||||
return self.get_data_source_choices(request, context)
|
||||
|
||||
def get_data_source_choices(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
data_sources = sahara.data_sources.list()
|
||||
|
||||
choices = [(data_source.id, data_source.name)
|
||||
for data_source in data_sources]
|
||||
choices.insert(0, (None, 'None'))
|
||||
|
||||
return choices
|
||||
|
||||
def populate_job_choices(self, request):
|
||||
sahara = saharaclient(request)
|
||||
jobs = sahara.jobs.list()
|
||||
|
||||
choices = [(job.id, job.name)
|
||||
for job in jobs]
|
||||
|
||||
return choices
|
||||
|
||||
class Meta:
|
||||
name = _("Job")
|
||||
help_text_template = "jobs/_launch_job_help.html"
|
||||
|
||||
|
||||
class JobExecutionExistingGeneralConfigAction(JobExecutionGeneralConfigAction):
|
||||
cluster = forms.ChoiceField(
|
||||
label=_("Cluster"),
|
||||
required=True,
|
||||
initial=(None, "None"),
|
||||
widget=forms.Select(attrs={"class": "cluster_choice"}))
|
||||
|
||||
def populate_cluster_choices(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
clusters = sahara.clusters.list()
|
||||
|
||||
choices = [(cluster.id, cluster.name)
|
||||
for cluster in clusters]
|
||||
|
||||
return choices
|
||||
|
||||
class Meta:
|
||||
name = _("Job")
|
||||
help_text_template = "jobs/_launch_job_help.html"
|
||||
|
||||
|
||||
class JobConfigAction(workflows.Action):
|
||||
MAIN_CLASS = "edp.java.main_class"
|
||||
JAVA_OPTS = "edp.java.java_opts"
|
||||
EDP_MAPPER = "edp.streaming.mapper"
|
||||
EDP_REDUCER = "edp.streaming.reducer"
|
||||
EDP_PREFIX = "edp."
|
||||
|
||||
property_name = forms.ChoiceField(
|
||||
required=False,
|
||||
)
|
||||
|
||||
job_configs = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
job_params = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
job_args_array = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
job_type = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
main_class = forms.CharField(label=_("Main Class"),
|
||||
required=False)
|
||||
|
||||
java_opts = forms.CharField(label=_("Java Opts"),
|
||||
required=False)
|
||||
|
||||
streaming_mapper = forms.CharField(label=_("Mapper"),
|
||||
required=True)
|
||||
|
||||
streaming_reducer = forms.CharField(label=_("Reducer"),
|
||||
required=True)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(JobConfigAction, self).__init__(request, *args, **kwargs)
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
if job_ex_id is not None:
|
||||
client = saharaclient(request)
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
job_ex = client.job_executions.get(job_ex_id)
|
||||
job_configs = job_ex.job_configs
|
||||
edp_configs = {}
|
||||
|
||||
if 'configs' in job_configs:
|
||||
configs, edp_configs = (
|
||||
self.clean_edp_configs(job_configs['configs']))
|
||||
self.fields['job_configs'].initial = (
|
||||
json.dumps(configs))
|
||||
|
||||
if 'params' in job_configs:
|
||||
self.fields['job_params'].initial = (
|
||||
json.dumps(job_configs['params']))
|
||||
job_args = json.dumps(job_configs['args'])
|
||||
self.fields['job_args_array'].initial = job_args
|
||||
|
||||
if self.MAIN_CLASS in edp_configs:
|
||||
self.fields['main_class'].initial = (
|
||||
edp_configs[self.MAIN_CLASS])
|
||||
if self.JAVA_OPTS in edp_configs:
|
||||
self.fields['java_opts'].initial = (
|
||||
edp_configs[self.JAVA_OPTS])
|
||||
|
||||
if self.EDP_MAPPER in edp_configs:
|
||||
self.fields['streaming_mapper'].initial = (
|
||||
edp_configs[self.EDP_MAPPER])
|
||||
if self.EDP_REDUCER in edp_configs:
|
||||
self.fields['streaming_reducer'].initial = (
|
||||
edp_configs[self.EDP_REDUCER])
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(workflows.Action, self).clean()
|
||||
job_type = cleaned_data.get("job_type", None)
|
||||
|
||||
if job_type != "MapReduce.Streaming":
|
||||
if "streaming_mapper" in self._errors:
|
||||
del self._errors["streaming_mapper"]
|
||||
if "streaming_reducer" in self._errors:
|
||||
del self._errors["streaming_reducer"]
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def populate_property_name_choices(self, request, context):
|
||||
client = saharaclient(request)
|
||||
job_id = request.REQUEST.get("job_id") or request.REQUEST.get("job")
|
||||
job_type = client.jobs.get(job_id).type
|
||||
job_configs = client.jobs.get_configs(job_type).job_config
|
||||
choices = [(param['value'], param['name'])
|
||||
for param in job_configs['configs']]
|
||||
return choices
|
||||
|
||||
def clean_edp_configs(self, configs):
|
||||
edp_configs = {}
|
||||
for key, value in configs.iteritems():
|
||||
if key.startswith(self.EDP_PREFIX):
|
||||
edp_configs[key] = value
|
||||
for rmkey in edp_configs.keys():
|
||||
del configs[rmkey]
|
||||
return (configs, edp_configs)
|
||||
|
||||
class Meta:
|
||||
name = _("Configure")
|
||||
help_text_template = "jobs/_launch_job_configure_help.html"
|
||||
|
||||
|
||||
class JobExecutionGeneralConfig(workflows.Step):
|
||||
action_class = JobExecutionGeneralConfigAction
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
if k in ["job_input", "job_output"]:
|
||||
context["job_general_" + k] = None if v == "None" else v
|
||||
else:
|
||||
context["job_general_" + k] = v
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class JobExecutionExistingGeneralConfig(workflows.Step):
|
||||
action_class = JobExecutionExistingGeneralConfigAction
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
if k in ["job_input", "job_output"]:
|
||||
context["job_general_" + k] = None if v == "None" else v
|
||||
else:
|
||||
context["job_general_" + k] = v
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class JobConfig(workflows.Step):
|
||||
action_class = JobConfigAction
|
||||
template_name = 'jobs/config_template.html'
|
||||
|
||||
def contribute(self, data, context):
|
||||
job_config = self.clean_configs(
|
||||
json.loads(data.get("job_configs", '{}')))
|
||||
job_params = self.clean_configs(
|
||||
json.loads(data.get("job_params", '{}')))
|
||||
job_args_array = self.clean_configs(
|
||||
json.loads(data.get("job_args_array", '[]')))
|
||||
job_type = data.get("job_type", '')
|
||||
|
||||
context["job_type"] = job_type
|
||||
context["job_config"] = {"configs": job_config}
|
||||
context["job_config"]["args"] = job_args_array
|
||||
|
||||
if job_type == "Java":
|
||||
context["job_config"]["configs"][JobConfigAction.MAIN_CLASS] = (
|
||||
data.get("main_class", ""))
|
||||
context["job_config"]["configs"][JobConfigAction.JAVA_OPTS] = (
|
||||
data.get("java_opts", ""))
|
||||
elif job_type == "MapReduce.Streaming":
|
||||
context["job_config"]["configs"][JobConfigAction.EDP_MAPPER] = (
|
||||
data.get("streaming_mapper", ""))
|
||||
context["job_config"]["configs"][JobConfigAction.EDP_REDUCER] = (
|
||||
data.get("streaming_reducer", ""))
|
||||
else:
|
||||
context["job_config"]["params"] = job_params
|
||||
|
||||
return context
|
||||
|
||||
@staticmethod
|
||||
def clean_configs(configs):
|
||||
cleaned_conf = None
|
||||
if isinstance(configs, dict):
|
||||
cleaned_conf = dict([(k.strip(), v.strip())
|
||||
for k, v in configs.items()
|
||||
if len(v.strip()) > 0 and len(k.strip()) > 0])
|
||||
elif isinstance(configs, list):
|
||||
cleaned_conf = list([v.strip() for v in configs
|
||||
if len(v.strip()) > 0])
|
||||
return cleaned_conf
|
||||
|
||||
|
||||
class NewClusterConfigAction(c_flow.GeneralConfigAction):
|
||||
persist_cluster = forms.BooleanField(
|
||||
label=_("Persist cluster after job exit"),
|
||||
required=False)
|
||||
|
||||
class Meta:
|
||||
name = _("Configure Cluster")
|
||||
help_text_template = (
|
||||
"clusters/_configure_general_help.html")
|
||||
|
||||
|
||||
class ClusterGeneralConfig(workflows.Step):
|
||||
action_class = NewClusterConfigAction
|
||||
contributes = ("hidden_configure_field", )
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context["cluster_general_" + k] = v
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class LaunchJob(workflows.Workflow):
|
||||
slug = "launch_job"
|
||||
name = _("Launch Job")
|
||||
finalize_button_name = _("Launch")
|
||||
success_message = _("Job launched")
|
||||
failure_message = _("Could not launch job")
|
||||
success_url = "horizon:sahara:job_executions:index"
|
||||
default_steps = (JobExecutionExistingGeneralConfig, JobConfig)
|
||||
|
||||
def handle(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
|
||||
sahara.job_executions.create(
|
||||
context["job_general_job"],
|
||||
context["job_general_cluster"],
|
||||
context["job_general_job_input"],
|
||||
context["job_general_job_output"],
|
||||
context["job_config"])
|
||||
return True
|
||||
|
||||
|
||||
class SelectHadoopPluginAction(t_flows.SelectPluginAction):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SelectHadoopPluginAction, self).__init__(request,
|
||||
*args,
|
||||
**kwargs)
|
||||
self.fields["job_id"] = forms.ChoiceField(
|
||||
label=_("Plugin name"),
|
||||
required=True,
|
||||
initial=request.GET.get("job_id") or request.POST.get("job_id"),
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
self.fields["job_configs"] = forms.ChoiceField(
|
||||
label=_("Job configs"),
|
||||
required=True,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
self.fields["job_args"] = forms.ChoiceField(
|
||||
label=_("Job args"),
|
||||
required=True,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
self.fields["job_params"] = forms.ChoiceField(
|
||||
label=_("Job params"),
|
||||
required=True,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
if job_ex_id is not None:
|
||||
self.fields["job_execution_id"] = forms.ChoiceField(
|
||||
label=_("Job Execution Id"),
|
||||
required=True,
|
||||
initial=request.REQUEST.get("job_execution_id"),
|
||||
widget=forms.HiddenInput(
|
||||
attrs={"class": "hidden_create_field"}))
|
||||
|
||||
client = saharaclient(request)
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
job_configs = client.job_executions.get(job_ex_id).job_configs
|
||||
|
||||
if "configs" in job_configs:
|
||||
self.fields["job_configs"].initial = (
|
||||
json.dumps(job_configs["configs"]))
|
||||
if "params" in job_configs:
|
||||
self.fields["job_params"].initial = (
|
||||
json.dumps(job_configs["params"]))
|
||||
if "args" in job_configs:
|
||||
self.fields["job_args"].initial = (
|
||||
json.dumps(job_configs["args"]))
|
||||
|
||||
class Meta:
|
||||
name = _("Select plugin and hadoop version for cluster")
|
||||
help_text_template = ("clusters/_create_general_help.html")
|
||||
|
||||
|
||||
class SelectHadoopPlugin(workflows.Step):
|
||||
action_class = SelectHadoopPluginAction
|
||||
|
||||
|
||||
class ChosePluginVersion(workflows.Workflow):
|
||||
slug = "lunch_job"
|
||||
name = _("Launch Job")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created")
|
||||
failure_message = _("Could not create")
|
||||
success_url = "horizon:sahara:cluster_templates:index"
|
||||
default_steps = (SelectHadoopPlugin,)
|
||||
|
||||
|
||||
class LaunchJobNewCluster(workflows.Workflow):
|
||||
slug = "launch_job"
|
||||
name = _("Launch Job")
|
||||
finalize_button_name = _("Launch")
|
||||
success_message = _("Job launched")
|
||||
failure_message = _("Could not launch job")
|
||||
success_url = "horizon:sahara:jobs:index"
|
||||
default_steps = (ClusterGeneralConfig,
|
||||
JobExecutionGeneralConfig,
|
||||
JobConfig)
|
||||
|
||||
def handle(self, request, context):
|
||||
sahara = saharaclient(request)
|
||||
node_groups = None
|
||||
|
||||
plugin, hadoop_version = (
|
||||
whelpers.get_plugin_and_hadoop_version(request))
|
||||
|
||||
ct_id = context["cluster_general_cluster_template"] or None
|
||||
user_keypair = context["cluster_general_keypair"] or None
|
||||
|
||||
cluster = sahara.clusters.create(
|
||||
context["cluster_general_cluster_name"],
|
||||
plugin, hadoop_version,
|
||||
cluster_template_id=ct_id,
|
||||
default_image_id=context["cluster_general_image"],
|
||||
description=context["cluster_general_description"],
|
||||
node_groups=node_groups,
|
||||
user_keypair_id=user_keypair,
|
||||
is_transient=not(context["cluster_general_persist_cluster"]),
|
||||
net_id=context.get("cluster_general_neutron_management_network",
|
||||
None))
|
||||
|
||||
sahara.job_executions.create(
|
||||
context["job_general_job"],
|
||||
cluster.id,
|
||||
context["job_general_job_input"],
|
||||
context["job_general_job_output"],
|
||||
context["job_config"])
|
||||
|
||||
return True
|
|
@ -1,27 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class NodegroupTemplatesPanel(horizon.Panel):
|
||||
name = _("Node Group Templates")
|
||||
slug = 'nodegroup_templates'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(NodegroupTemplatesPanel)
|
|
@ -1,91 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django import template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateNodegroupTemplate(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Template")
|
||||
url = "horizon:sahara:nodegroup_templates:create-nodegroup-template"
|
||||
classes = ("ajax-modal", "btn-create", "create-nodegrouptemplate-btn")
|
||||
|
||||
|
||||
class ConfigureNodegroupTemplate(tables.LinkAction):
|
||||
name = "configure"
|
||||
verbose_name = _("Configure Template")
|
||||
url = "horizon:sahara:nodegroup_templates:configure-nodegroup-template"
|
||||
classes = ("ajax-modal", "btn-create", "configure-nodegrouptemplate-btn")
|
||||
attrs = {"style": "display: none"}
|
||||
|
||||
|
||||
class CopyTemplate(tables.LinkAction):
|
||||
name = "copy"
|
||||
verbose_name = _("Copy Template")
|
||||
url = "horizon:sahara:nodegroup_templates:copy"
|
||||
classes = ("ajax-modal", )
|
||||
|
||||
|
||||
class DeleteTemplate(tables.BatchAction):
|
||||
name = "delete_nodegroup_template"
|
||||
verbose_name = _("Delete")
|
||||
classes = ("btn-terminate", "btn-danger")
|
||||
|
||||
action_present = _("Delete")
|
||||
action_past = _("Deleted")
|
||||
data_type_singular = _("Template")
|
||||
data_type_plural = _("Templates")
|
||||
|
||||
def allowed(self, request, template):
|
||||
return True
|
||||
|
||||
def action(self, request, template_id):
|
||||
sahara = saharaclient(request)
|
||||
sahara.node_group_templates.delete(template_id)
|
||||
|
||||
|
||||
def render_processes(nodegroup_template):
|
||||
template_name = 'nodegroup_templates/_processes_list.html'
|
||||
context = {"processes": nodegroup_template.node_processes}
|
||||
return template.loader.render_to_string(template_name, context)
|
||||
|
||||
|
||||
class NodegroupTemplatesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:nodegroup_templates:details"))
|
||||
plugin_name = tables.Column("plugin_name",
|
||||
verbose_name=_("Plugin"))
|
||||
hadoop_version = tables.Column("hadoop_version",
|
||||
verbose_name=_("Hadoop Version"))
|
||||
node_processes = tables.Column(render_processes,
|
||||
verbose_name=_("Node Processes"))
|
||||
|
||||
class Meta:
|
||||
name = "nodegroup_templates"
|
||||
verbose_name = _("Node Group Templates")
|
||||
table_actions = (CreateNodegroupTemplate,
|
||||
ConfigureNodegroupTemplate,
|
||||
DeleteTemplate)
|
||||
row_actions = (CopyTemplate,
|
||||
DeleteTemplate,)
|
|
@ -1,60 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
# horizon.api is for backward compatibility with folsom
|
||||
nova = importutils.import_any('openstack_dashboard.api.nova',
|
||||
'horizon.api.nova')
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralTab(tabs.Tab):
|
||||
name = _("General Info")
|
||||
slug = "nodegroup_template_details_tab"
|
||||
template_name = ("nodegroup_templates/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
template_id = self.tab_group.kwargs['template_id']
|
||||
sahara = saharaclient(request)
|
||||
template = sahara.node_group_templates.get(template_id)
|
||||
flavor = nova.flavor_get(request, template.flavor_id)
|
||||
return {"template": template, "flavor": flavor}
|
||||
|
||||
|
||||
class ConfigsTab(tabs.Tab):
|
||||
name = _("Service Configurations")
|
||||
slug = "nodegroup_template_service_configs_tab"
|
||||
template_name = ("nodegroup_templates/_service_confs.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
template_id = self.tab_group.kwargs['template_id']
|
||||
sahara = saharaclient(request)
|
||||
template = sahara.node_group_templates.get(template_id)
|
||||
return {"template": template}
|
||||
|
||||
|
||||
class NodegroupTemplateDetailsTabs(tabs.TabGroup):
|
||||
slug = "nodegroup_template_details"
|
||||
tabs = (GeneralTab, ConfigsTab, )
|
||||
sticky = True
|
|
@ -1,44 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
import saharadashboard.nodegroup_templates.views as views
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('sahara.nodegroup_templates.views',
|
||||
url(r'^$', views.NodegroupTemplatesView.as_view(),
|
||||
name='index'),
|
||||
url(r'^nodegroup-templates$',
|
||||
views.NodegroupTemplatesView.as_view(),
|
||||
name='nodegroup-templates'),
|
||||
url(r'^create-nodegroup-template$',
|
||||
views.CreateNodegroupTemplateView.as_view(),
|
||||
name='create-nodegroup-template'),
|
||||
url(r'^configure-nodegroup-template$',
|
||||
views.ConfigureNodegroupTemplateView.as_view(),
|
||||
name='configure-nodegroup-template'),
|
||||
url(r'^(?P<template_id>[^/]+)$',
|
||||
views.NodegroupTemplateDetailsView.as_view(),
|
||||
name='details'),
|
||||
url(r'^(?P<template_id>[^/]+)/copy$',
|
||||
views.CopyNodegroupTemplateView.as_view(),
|
||||
name='copy')
|
||||
)
|
|
@ -1,91 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.nodegroup_templates.tables as _tables
|
||||
import saharadashboard.nodegroup_templates.tabs as _tabs
|
||||
import saharadashboard.nodegroup_templates.workflows.copy as copy_flow
|
||||
import saharadashboard.nodegroup_templates.workflows.create as create_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NodegroupTemplatesView(tables.DataTableView):
|
||||
table_class = _tables.NodegroupTemplatesTable
|
||||
template_name = 'nodegroup_templates/nodegroup_templates.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
nodegroup_templates = sahara.node_group_templates.list()
|
||||
return nodegroup_templates
|
||||
|
||||
|
||||
class NodegroupTemplateDetailsView(tabs.TabView):
|
||||
tab_group_class = _tabs.NodegroupTemplateDetailsTabs
|
||||
template_name = 'nodegroup_templates/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(NodegroupTemplateDetailsView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
class CreateNodegroupTemplateView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.CreateNodegroupTemplate
|
||||
success_url = \
|
||||
"horizon:sahara:nodegroup_templates:create-nodegroup-template"
|
||||
classes = ("ajax-modal")
|
||||
template_name = "nodegroup_templates/create.html"
|
||||
|
||||
|
||||
class ConfigureNodegroupTemplateView(workflows.WorkflowView):
|
||||
workflow_class = create_flow.ConfigureNodegroupTemplate
|
||||
success_url = "horizon:sahara:nodegroup_templates"
|
||||
template_name = "nodegroup_templates/configure.html"
|
||||
|
||||
|
||||
class CopyNodegroupTemplateView(workflows.WorkflowView):
|
||||
workflow_class = copy_flow.CopyNodegroupTemplate
|
||||
success_url = "horizon:sahara:nodegroup_templates"
|
||||
template_name = "nodegroup_templates/configure.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CopyNodegroupTemplateView, self)\
|
||||
.get_context_data(**kwargs)
|
||||
|
||||
context["template_id"] = kwargs["template_id"]
|
||||
return context
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
template_id = self.kwargs['template_id']
|
||||
sahara = saharaclient(self.request)
|
||||
template = sahara.node_group_templates.get(template_id)
|
||||
self._object = template
|
||||
return self._object
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(CopyNodegroupTemplateView, self).get_initial()
|
||||
initial.update({'template_id': self.kwargs['template_id']})
|
||||
return initial
|
|
@ -1,80 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
import saharadashboard.nodegroup_templates.workflows.create as create_flow
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CopyNodegroupTemplate(create_flow.ConfigureNodegroupTemplate):
|
||||
success_message = _("Node Group Template copy %s created")
|
||||
|
||||
def __init__(self, request, context_seed, entry_point, *args, **kwargs):
|
||||
sahara = saharaclient(request)
|
||||
|
||||
template_id = context_seed["template_id"]
|
||||
template = sahara.node_group_templates.get(template_id)
|
||||
self._set_configs_to_copy(template.node_configs)
|
||||
|
||||
plugin = template.plugin_name
|
||||
hadoop_version = template.hadoop_version
|
||||
|
||||
request.GET = request.GET.copy()
|
||||
request.GET.update({"plugin_name": plugin})
|
||||
request.GET.update({"hadoop_version": hadoop_version})
|
||||
|
||||
super(CopyNodegroupTemplate, self).__init__(request, context_seed,
|
||||
entry_point, *args,
|
||||
**kwargs)
|
||||
|
||||
for step in self.steps:
|
||||
if not isinstance(step, create_flow.GeneralConfig):
|
||||
continue
|
||||
fields = step.action.fields
|
||||
|
||||
fields["nodegroup_name"].initial = template.name + "-copy"
|
||||
fields["description"].initial = template.description
|
||||
fields["flavor"].initial = template.flavor_id
|
||||
|
||||
storage = "cinder_volume" if template.volumes_per_node > 0 \
|
||||
else "ephemeral_drive"
|
||||
volumes_per_node = template.volumes_per_node
|
||||
volumes_size = template.volumes_size
|
||||
fields["storage"].initial = storage
|
||||
fields["volumes_per_node"].initial = volumes_per_node
|
||||
fields["volumes_size"].initial = volumes_size
|
||||
|
||||
if template.floating_ip_pool:
|
||||
fields['floating_ip_pool'].initial = template.floating_ip_pool
|
||||
|
||||
processes_dict = dict()
|
||||
plugin_details = sahara.plugins.get_version_details(
|
||||
plugin,
|
||||
hadoop_version)
|
||||
plugin_node_processes = plugin_details.node_processes
|
||||
for process in template.node_processes:
|
||||
# need to know the service
|
||||
_service = None
|
||||
for service, processes in plugin_node_processes.items():
|
||||
if process in processes:
|
||||
_service = service
|
||||
break
|
||||
processes_dict.update({"%s:%s" % (_service, process): process})
|
||||
fields["processes"].initial = processes_dict
|
|
@ -1,299 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
from saharaclient.api import base as api_base
|
||||
|
||||
from saharadashboard.api import client as saharaclient
|
||||
import saharadashboard.api.helpers as helpers
|
||||
from saharadashboard.utils import importutils
|
||||
import saharadashboard.utils.workflow_helpers as whelpers
|
||||
|
||||
|
||||
# horizon.api is for backward compatibility with folsom
|
||||
nova = importutils.import_any('openstack_dashboard.api.nova',
|
||||
'horizon.api.nova')
|
||||
|
||||
network = importutils.import_any('openstack_dashboard.api.network',
|
||||
'horizon.api.network')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GeneralConfigAction(workflows.Action):
|
||||
nodegroup_name = forms.CharField(label=_("Template Name"),
|
||||
required=True)
|
||||
|
||||
description = forms.CharField(label=_("Description"),
|
||||
required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
flavor = forms.ChoiceField(label=_("OpenStack Flavor"),
|
||||
required=True)
|
||||
|
||||
storage = forms.ChoiceField(
|
||||
label=_("Storage location"),
|
||||
required=True,
|
||||
help_text=_("Storage"),
|
||||
choices=[("ephemeral_drive", "Ephemeral Drive"),
|
||||
("cinder_volume", "Cinder Volume")],
|
||||
widget=forms.Select(attrs={"class": "storage_field"}))
|
||||
|
||||
volumes_per_node = forms.IntegerField(
|
||||
label=_("Volumes per node"),
|
||||
required=False,
|
||||
initial=1,
|
||||
widget=forms.TextInput(attrs={"class": "volume_per_node_field"})
|
||||
)
|
||||
|
||||
volumes_size = forms.IntegerField(
|
||||
label=_("Volumes size (GB)"),
|
||||
required=False,
|
||||
initial=10,
|
||||
widget=forms.TextInput(attrs={"class": "volume_size_field"})
|
||||
)
|
||||
|
||||
hidden_configure_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_configure_field"}))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
hlps = helpers.Helpers(sahara)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
process_choices = []
|
||||
version_details = sahara.plugins.get_version_details(plugin,
|
||||
hadoop_version)
|
||||
|
||||
for service, processes in version_details.node_processes.items():
|
||||
for process in processes:
|
||||
process_choices.append(
|
||||
(str(service) + ":" + str(process), process))
|
||||
|
||||
if not saharaclient.AUTO_ASSIGNMENT_ENABLED:
|
||||
pools = network.floating_ip_pools_list(request)
|
||||
pool_choices = [(pool.id, pool.name) for pool in pools]
|
||||
pool_choices.insert(0, (None, "Do not assign floating IPs"))
|
||||
|
||||
self.fields['floating_ip_pool'] = forms.ChoiceField(
|
||||
label=_("Floating IP pool"),
|
||||
choices=pool_choices,
|
||||
required=False)
|
||||
|
||||
self.fields["processes"] = forms.MultipleChoiceField(
|
||||
label=_("Processes"),
|
||||
required=True,
|
||||
widget=forms.CheckboxSelectMultiple(),
|
||||
help_text=_("Processes to be launched in node group"),
|
||||
choices=process_choices)
|
||||
|
||||
self.fields["plugin_name"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=plugin
|
||||
)
|
||||
self.fields["hadoop_version"] = forms.CharField(
|
||||
widget=forms.HiddenInput(),
|
||||
initial=hadoop_version
|
||||
)
|
||||
|
||||
node_parameters = hlps.get_general_node_group_configs(plugin,
|
||||
hadoop_version)
|
||||
for param in node_parameters:
|
||||
self.fields[param.name] = whelpers.build_control(param)
|
||||
|
||||
def populate_flavor_choices(self, request, context):
|
||||
try:
|
||||
flavors = nova.flavor_list(request)
|
||||
flavor_list = [(flavor.id, "%s" % flavor.name)
|
||||
for flavor in flavors]
|
||||
except Exception:
|
||||
flavor_list = []
|
||||
exceptions.handle(request,
|
||||
_('Unable to retrieve instance flavors.'))
|
||||
return sorted(flavor_list)
|
||||
|
||||
def get_help_text(self):
|
||||
extra = dict()
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(self.request)
|
||||
extra["plugin_name"] = plugin
|
||||
extra["hadoop_version"] = hadoop_version
|
||||
return super(GeneralConfigAction, self).get_help_text(extra)
|
||||
|
||||
class Meta:
|
||||
name = _("Configure Node Group Template")
|
||||
help_text_template = \
|
||||
("nodegroup_templates/_configure_general_help.html")
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
contributes = ("general_nodegroup_name", )
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
if "hidden" in k:
|
||||
continue
|
||||
context["general_" + k] = v if v != "None" else None
|
||||
|
||||
post = self.workflow.request.POST
|
||||
context['general_processes'] = post.getlist("processes")
|
||||
return context
|
||||
|
||||
|
||||
class ConfigureNodegroupTemplate(whelpers.ServiceParametersWorkflow,
|
||||
whelpers.StatusFormatMixin):
|
||||
slug = "configure_nodegroup_template"
|
||||
name = _("Create Node Group Template")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created Node Group Template %s")
|
||||
name_property = "general_nodegroup_name"
|
||||
success_url = "horizon:sahara:nodegroup_templates:index"
|
||||
default_steps = (GeneralConfig,)
|
||||
|
||||
def __init__(self, request, context_seed, entry_point, *args, **kwargs):
|
||||
sahara = saharaclient.client(request)
|
||||
hlps = helpers.Helpers(sahara)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
general_parameters = hlps.get_general_node_group_configs(
|
||||
plugin,
|
||||
hadoop_version)
|
||||
service_parameters = hlps.get_targeted_node_group_configs(
|
||||
plugin,
|
||||
hadoop_version)
|
||||
|
||||
self._populate_tabs(general_parameters, service_parameters)
|
||||
|
||||
super(ConfigureNodegroupTemplate, self).__init__(request,
|
||||
context_seed,
|
||||
entry_point,
|
||||
*args, **kwargs)
|
||||
|
||||
def is_valid(self):
|
||||
missing = self.depends_on - set(self.context.keys())
|
||||
if missing:
|
||||
raise exceptions.WorkflowValidationError(
|
||||
"Unable to complete the workflow. The values %s are "
|
||||
"required but not present." % ", ".join(missing))
|
||||
checked_steps = []
|
||||
|
||||
if "general_processes" in self.context:
|
||||
checked_steps = self.context["general_processes"]
|
||||
enabled_services = set([])
|
||||
for process_name in checked_steps:
|
||||
enabled_services.add(str(process_name).split(":")[0])
|
||||
|
||||
steps_valid = True
|
||||
for step in self.steps:
|
||||
process_name = str(getattr(step, "process_name", None))
|
||||
if process_name not in enabled_services and \
|
||||
not isinstance(step, GeneralConfig):
|
||||
continue
|
||||
if not step.action.is_valid():
|
||||
steps_valid = False
|
||||
step.has_errors = True
|
||||
if not steps_valid:
|
||||
return steps_valid
|
||||
return self.validate(self.context)
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
sahara = saharaclient.client(request)
|
||||
|
||||
processes = []
|
||||
for service_process in context["general_processes"]:
|
||||
processes.append(str(service_process).split(":")[1])
|
||||
|
||||
configs_dict = whelpers.parse_configs_from_context(context,
|
||||
self.defaults)
|
||||
|
||||
plugin, hadoop_version = whelpers.\
|
||||
get_plugin_and_hadoop_version(request)
|
||||
|
||||
volumes_per_node = None
|
||||
volumes_size = None
|
||||
|
||||
if context["general_storage"] == "cinder_volume":
|
||||
volumes_per_node = context["general_volumes_per_node"]
|
||||
volumes_size = context["general_volumes_size"]
|
||||
|
||||
sahara.node_group_templates.create(
|
||||
name=context["general_nodegroup_name"],
|
||||
plugin_name=plugin,
|
||||
hadoop_version=hadoop_version,
|
||||
description=context["general_description"],
|
||||
flavor_id=context["general_flavor"],
|
||||
volumes_per_node=volumes_per_node,
|
||||
volumes_size=volumes_size,
|
||||
node_processes=processes,
|
||||
node_configs=configs_dict,
|
||||
floating_ip_pool=context.get("general_floating_ip_pool", None))
|
||||
return True
|
||||
except api_base.APIException as e:
|
||||
self.error_description = str(e)
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
|
||||
|
||||
class SelectPluginAction(workflows.Action,
|
||||
whelpers.PluginAndVersionMixin):
|
||||
hidden_create_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_create_field"}))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SelectPluginAction, self).__init__(request, *args, **kwargs)
|
||||
|
||||
sahara = saharaclient.client(request)
|
||||
self._generate_plugin_version_fields(sahara)
|
||||
|
||||
class Meta:
|
||||
name = _("Select plugin and hadoop version")
|
||||
help_text_template = ("nodegroup_templates/_create_general_help.html")
|
||||
|
||||
|
||||
class SelectPlugin(workflows.Step):
|
||||
action_class = SelectPluginAction
|
||||
contributes = ("plugin_name", "hadoop_version")
|
||||
|
||||
def contribute(self, data, context):
|
||||
context = super(SelectPlugin, self).contribute(data, context)
|
||||
context["plugin_name"] = data.get('plugin_name', None)
|
||||
context["hadoop_version"] = \
|
||||
data.get(context["plugin_name"] + "_version", None)
|
||||
return context
|
||||
|
||||
|
||||
class CreateNodegroupTemplate(workflows.Workflow):
|
||||
slug = "create_nodegroup_template"
|
||||
name = _("Create Node Group Template")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _("Created")
|
||||
failure_message = _("Could not create")
|
||||
success_url = "horizon:sahara:nodegroup_templates:index"
|
||||
default_steps = (SelectPlugin,)
|
|
@ -1,17 +0,0 @@
|
|||
#
|
||||
# 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 six
|
||||
|
||||
|
||||
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
|
|
@ -1,73 +0,0 @@
|
|||
# Copyright 2011 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 related utilities and helper functions.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class."""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
__import__(mod_str)
|
||||
try:
|
||||
return getattr(sys.modules[mod_str], class_str)
|
||||
except AttributeError:
|
||||
raise ImportError('Class %s cannot be found (%s)' %
|
||||
(class_str,
|
||||
traceback.format_exception(*sys.exc_info())))
|
||||
|
||||
|
||||
def import_object(import_str, *args, **kwargs):
|
||||
"""Import a class and return an instance of it."""
|
||||
return import_class(import_str)(*args, **kwargs)
|
||||
|
||||
|
||||
def import_object_ns(name_space, import_str, *args, **kwargs):
|
||||
"""Tries to import object from default namespace.
|
||||
|
||||
Imports a class and return an instance of it, first by trying
|
||||
to find the class in a default namespace, then failing back to
|
||||
a full path if not found in the default namespace.
|
||||
"""
|
||||
import_value = "%s.%s" % (name_space, import_str)
|
||||
try:
|
||||
return import_class(import_value)(*args, **kwargs)
|
||||
except ImportError:
|
||||
return import_class(import_str)(*args, **kwargs)
|
||||
|
||||
|
||||
def import_module(import_str):
|
||||
"""Import a module."""
|
||||
__import__(import_str)
|
||||
return sys.modules[import_str]
|
||||
|
||||
|
||||
def import_versioned_module(version, submodule=None):
|
||||
module = 'saharadashboard.v%s' % version
|
||||
if submodule:
|
||||
module = '.'.join((module, submodule))
|
||||
return import_module(module)
|
||||
|
||||
|
||||
def try_import(import_str, default=None):
|
||||
"""Try to import a module and if it fails return default."""
|
||||
try:
|
||||
return import_module(import_str)
|
||||
except ImportError:
|
||||
return default
|
|
@ -1,27 +0,0 @@
|
|||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
from saharadashboard import dashboard
|
||||
|
||||
|
||||
class PluginsPanel(horizon.Panel):
|
||||
name = _("Plugins")
|
||||
slug = 'plugins'
|
||||
|
||||
|
||||
dashboard.SaharaDashboard.register(PluginsPanel)
|
|
@ -1,46 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django import template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def render_versions(plugin):
|
||||
template_name = 'plugins/_versions_list.html'
|
||||
context = {"plugin": plugin}
|
||||
return template.loader.render_to_string(template_name, context)
|
||||
|
||||
|
||||
class PluginsTable(tables.DataTable):
|
||||
title = tables.Column("title",
|
||||
verbose_name=_("Name"),
|
||||
link=("horizon:sahara:plugins:details"))
|
||||
|
||||
versions = tables.Column(render_versions,
|
||||
verbose_name=_("Supported Hadoop Versions"))
|
||||
|
||||
description = tables.Column("description",
|
||||
verbose_name=_("Plugin Description"))
|
||||
|
||||
class Meta:
|
||||
name = "plugins"
|
||||
verbose_name = _("Plugins")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
|
@ -1,41 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DetailsTab(tabs.Tab):
|
||||
name = _("Details")
|
||||
slug = "plugin_details_tab"
|
||||
template_name = ("plugins/_details.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
plugin_id = self.tab_group.kwargs['plugin_id']
|
||||
sahara = saharaclient(request)
|
||||
plugin = sahara.plugins.get(plugin_id)
|
||||
return {"plugin": plugin}
|
||||
|
||||
|
||||
class PluginDetailsTabs(tabs.TabGroup):
|
||||
slug = "cluster_details"
|
||||
tabs = (DetailsTab,)
|
||||
sticky = True
|
|
@ -1,32 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
from saharadashboard.plugins.views import PluginDetailsView
|
||||
from saharadashboard.plugins.views import PluginsView
|
||||
from saharadashboard.utils import importutils
|
||||
|
||||
urls = importutils.import_any('django.conf.urls.defaults',
|
||||
'django.conf.urls')
|
||||
patterns = urls.patterns
|
||||
url = urls.url
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', PluginsView.as_view(), name='index'),
|
||||
url(r'^$', PluginsView.as_view(), name='plugins'),
|
||||
url(r'^(?P<plugin_id>[^/]+)$',
|
||||
PluginDetailsView.as_view(), name='details'),
|
||||
)
|
|
@ -1,46 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
|
||||
from saharadashboard.api.client import client as saharaclient
|
||||
from saharadashboard.plugins.tables import PluginsTable
|
||||
from saharadashboard.plugins.tabs import PluginDetailsTabs
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginsView(tables.DataTableView):
|
||||
table_class = PluginsTable
|
||||
template_name = 'plugins/plugins.html'
|
||||
|
||||
def get_data(self):
|
||||
sahara = saharaclient(self.request)
|
||||
return sahara.plugins.list()
|
||||
|
||||
|
||||
class PluginDetailsView(tabs.TabView):
|
||||
tab_group_class = PluginDetailsTabs
|
||||
template_name = 'plugins/details.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(PluginDetailsView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_data(self):
|
||||
pass
|
|
@ -1,21 +0,0 @@
|
|||
<div class="well">
|
||||
<p>
|
||||
This Cluster Template will be created for:
|
||||
<br >
|
||||
<b>Plugin</b>: {{ plugin_name }}
|
||||
<br />
|
||||
<b>Hadoop version</b>: {{ hadoop_version }}
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
The Cluster Template object should specify Node Group Templates that will be used to build a Hadoop Cluster.
|
||||
You can add Node Groups using Node Group Templates on a "Node Groups" tab.
|
||||
</p>
|
||||
<p>
|
||||
You may set <b>cluster</b> scoped Hadoop configurations on corresponding tabs.
|
||||
</p>
|
||||
<p>
|
||||
The Cluster Template object may specify a list of processes in anti-affinity group.
|
||||
That means these processes may not be launched more than once on a single host.
|
||||
</p>
|
||||
</div>
|
|
@ -1,3 +0,0 @@
|
|||
<p class="well">
|
||||
Select a plugin and Hadoop version for a new Cluster template.
|
||||
</p>
|
|
@ -1,54 +0,0 @@
|
|||
{% load i18n sizeformat %}
|
||||
{% load url from future %}
|
||||
<h3>{% trans "Template Overview" %}</h3>
|
||||
<div class="status row-fluid detail">
|
||||
<dl>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ template.name }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ template.id }}</dd>
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ template.description|default:"None" }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Plugin" %}</dt>
|
||||
<dd><a href="{% url 'horizon:sahara:plugins:details' template.plugin_name %}">{{ template.plugin_name }}</a></dd>
|
||||
<dt>{% trans "Hadoop Version" %}</dt>
|
||||
<dd>{{ template.hadoop_version }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Anti-affinity enabled for" %}</dt>
|
||||
{% if template.anti_affinity %}
|
||||
<dd>
|
||||
<ul>
|
||||
{% for process in template.anti_affinity %}
|
||||
<li>{{ process }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
{% else %}
|
||||
<h6>{% trans "no processes" %}</h6>
|
||||
{% endif %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Node Configurations" %}</dt>
|
||||
{% if template.cluster_configs %}
|
||||
<dd>
|
||||
{% for service, service_conf in template.cluster_configs.items %}
|
||||
<h4>{{ service }}</h4>
|
||||
{% if service_conf %}
|
||||
<ul>
|
||||
{% for conf_name, conf_value in service_conf.items %}
|
||||
<li>{{ conf_name }}: {{ conf_value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h6>No configurations</h6>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Cluster configurations are not specified" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
|
@ -1,55 +0,0 @@
|
|||
{% load i18n sizeformat %}
|
||||
{% load url from future %}
|
||||
<h3>{% trans "Node Groups" %}</h3>
|
||||
<div class="status row-fluid detail">
|
||||
{% for node_group in template.node_groups %}
|
||||
<dl class="well">
|
||||
<h4>{% trans "Node Group" %}: {{ node_group.name }}</h4>
|
||||
<dt>{% trans "Nodes Count" %}</dt>
|
||||
<dd>{{ node_group.count }}</dd>
|
||||
|
||||
<dt>{% trans "Flavor" %}</dt>
|
||||
<dd>{{ node_group.flavor_id|default:"Flavor is not specified" }}</dd>
|
||||
|
||||
<dt>{% trans "Template" %}</dt>
|
||||
{% if node_group.node_group_template_id %}
|
||||
<dd><a href="{% url 'horizon:sahara:nodegroup_templates:details' node_group.node_group_template_id %}">{{ node_group.node_group_template.name }} </a></dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Template not specified" %}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt>{% trans "Node Processes" %}</dt>
|
||||
{% if node_group.node_processes %}
|
||||
<dd>
|
||||
<ul>
|
||||
{% for process in node_group.node_processes %}
|
||||
<li>{{ process }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Node processes are not specified" %}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt>{% trans "Node Configurations" %}</dt>
|
||||
{% if node_group.node_configs %}
|
||||
<dd>
|
||||
{% for service, service_conf in node_group.node_configs.items %}
|
||||
<h6>{{ service }}</h6>
|
||||
{% if service_conf %}
|
||||
<ul>
|
||||
{% for conf_name, conf_value in service_conf.items %}
|
||||
<li>{{ conf_name }}: {{ conf_value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h6>No configurations</h6>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Node configurations are not specified" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endfor %}
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<ul>
|
||||
{% for group in node_groups %}
|
||||
<li>{{ group.name }}: {{ group.count }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
|
@ -1,24 +0,0 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
|
||||
{% load url from future %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}upload_file{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:sahara:cluster_templates:upload_file' %}{% endblock %}
|
||||
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Upload Template" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" id="upload_file_btn" type="submit" value="{% trans "Upload" %}"/>
|
||||
<a href="{% url 'horizon:sahara:cluster_templates:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -1,155 +0,0 @@
|
|||
<script>
|
||||
var template = '<tr id_attr="$id"><td>' +
|
||||
'<div class="input control-group" style="padding-right:15px;">' +
|
||||
'<input id="template_id_$id" value="$template_id" type="hidden" name="template_id_$id">' +
|
||||
'<input id="group_name_$id" value="$group_name" type="text" name="group_name_$id" class="input-medium">' +
|
||||
'</div>' +
|
||||
'</td>' +
|
||||
'<td>' +
|
||||
'<div class="input control-group" style="padding-right:15px;"><input disabled value="$template_name" class="input-medium" /></div>' +
|
||||
'</td>' +
|
||||
'<td>' +
|
||||
'<div class="input control-group btn-group input-append" style="float:left;padding-right:5px;">' +
|
||||
'<input id="count_$id" class="count-field" value="$node_count" type="text" max="4" maxlength="4" name="count_$id" size="4" style="width:50px">' +
|
||||
'<div class="btn dec-btn" data-count-id="count_$id"><i class="icon-minus"></i></div>' +
|
||||
'<div class="btn inc-btn" data-count-id="count_$id"><i class="icon-plus"></i></div>' +
|
||||
'</div>' +
|
||||
'<div class="input" style="float:left">' +
|
||||
|
||||
'</div>' +
|
||||
'</td>' +
|
||||
'<td>' +
|
||||
'<div class="input control-group" style="float:left;padding-right:5px;">' +
|
||||
'<input type="button" class="btn btn-danger" id="delete_btn_$id" data-toggle="dropdown" onclick="delete_node_group(this)" value="Remove" style="margin-bottom: 10px"/>' +
|
||||
'</div>' +
|
||||
'</td>' +
|
||||
|
||||
'</tr>';
|
||||
|
||||
function mark_element_as_wrong(id){
|
||||
$("#"+id).parent("div").addClass("error");
|
||||
}
|
||||
|
||||
function get_next_id() {
|
||||
var max = -1;
|
||||
$("#node-templates tbody tr").each(function () {
|
||||
max = Math.max(max, parseInt($(this).attr("id_attr")));
|
||||
});
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
function set_nodes_ids() {
|
||||
var ids = [];
|
||||
$("#node-templates tbody tr").each(function () {
|
||||
ids.push(parseInt($(this).attr("id_attr")));
|
||||
});
|
||||
$("#forms_ids").val(JSON.stringify(ids));
|
||||
}
|
||||
|
||||
function add_node(node_count, group_name, template_id, id, deletable) {
|
||||
var template_name = $("select option[value='" + template_id + "']").html();
|
||||
var tmp = template.
|
||||
replace(/\$id/g, id).
|
||||
replace(/\$group_name/g, group_name).
|
||||
replace(/\$template_id/g, template_id).
|
||||
replace(/\$node_count/g, node_count).
|
||||
replace(/\$template_name/g, template_name);
|
||||
$("#node-templates tbody").append(tmp);
|
||||
if (!deletable) {
|
||||
$("#delete_btn_" + id).remove();
|
||||
$("#group_name_" + id).prop('readonly', true);
|
||||
}
|
||||
$("#node-templates").show();
|
||||
set_nodes_ids();
|
||||
}
|
||||
|
||||
function add_node_group_template(node_count) {
|
||||
if ($("select option:selected").html() == "Select") {
|
||||
return;
|
||||
}
|
||||
var template_id = $("#template_id option:selected").val();
|
||||
var template_name = $("#template_id option:selected").html();
|
||||
add_node(node_count, template_name, template_id, get_next_id(), true);
|
||||
$(".count-field").change();
|
||||
}
|
||||
function delete_node_group(el) {
|
||||
var tr = $(el).parents("tr")[0];
|
||||
tr.parentNode.removeChild(tr);
|
||||
var id = get_next_id();
|
||||
if (id == 0) {
|
||||
$("#node-templates").hide();
|
||||
}
|
||||
set_nodes_ids();
|
||||
}
|
||||
$("#template_id").change(function () {
|
||||
if ($("select option:selected").html() == "Select") {
|
||||
$("#add_group_button").addClass("disabled");
|
||||
} else {
|
||||
$("#add_group_button").removeClass("disabled");
|
||||
}
|
||||
});
|
||||
$("#node-templates").hide();
|
||||
</script>
|
||||
<input type="hidden" value="[]" name="forms_ids" id="forms_ids">
|
||||
<div class="input">
|
||||
<select id="template_id" name="template">
|
||||
<option>Select</option>
|
||||
{% for template in form.templates %}
|
||||
<option value="{{ template.id }}">{{ template.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<a id="add_group_button" class="btn disabled btn-inline" onclick="add_node_group_template(1);">+</a>
|
||||
</div>
|
||||
<br/>
|
||||
<div id="node-templates">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td><label style="padding-bottom:5px">Group Name</label></td>
|
||||
<td><label style="padding-bottom:5px">Template </label></td>
|
||||
<td><label style="padding-bottom:5px">Count</label></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
{% for group in form.groups %}
|
||||
add_node("{{ group.count }}", "{{ group.name }}", "{{ group.template_id }}", "{{ group.id }}", {{ group.deletable }});
|
||||
{% endfor %}
|
||||
{% for field_id in form.errors_fields %}
|
||||
mark_element_as_wrong("{{ field_id }}");
|
||||
{% endfor %}
|
||||
|
||||
var handlers_registred;
|
||||
var lower_limit = 1;
|
||||
$(function() {
|
||||
if (!handlers_registred) {
|
||||
handlers_registred = true;
|
||||
$(".inc-btn").live("click", function(e) {
|
||||
var id = $(this).attr("data-count-id");
|
||||
$("#" + id).val(parseInt($("#" + id).val()) + 1);
|
||||
$(".count-field").change();
|
||||
});
|
||||
$(".dec-btn").live("click", function(e) {
|
||||
var id = $(this).attr("data-count-id");
|
||||
var val = parseInt($("#" + id).val());
|
||||
if (val > lower_limit) {
|
||||
$("#" + id).val(val - 1);
|
||||
}
|
||||
$(".count-field").change();
|
||||
});
|
||||
}
|
||||
|
||||
$(".count-field").live("change", function() {
|
||||
var val = $(this).val();
|
||||
if (val > lower_limit) {
|
||||
$(this).parent("div").find(".dec-btn").removeClass("disabled");
|
||||
} else {
|
||||
$(this).parent("div").find(".dec-btn").addClass("disabled");
|
||||
}
|
||||
}).change();
|
||||
});
|
||||
</script>
|
|
@ -1,66 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Sahara" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Cluster Templates") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="cluster_templates">
|
||||
{{ cluster_templates_table.render }}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
addHorizonLoadEvent(function () {
|
||||
horizon.modals.addModalInitFunction(function (modal) {
|
||||
if ($(modal).find(".nav-tabs").find("li").size() == 1) {
|
||||
// hide tab bar for plugin/version modal wizard
|
||||
$('div#modal_wrapper ul.nav-tabs').hide();
|
||||
}
|
||||
|
||||
$(".hidden_nodegroups_field").after("<input type='button' id='add_nodegroup' value='Add Node group'/><br/>");
|
||||
$("#add_nodegroup").click(function() {
|
||||
$(".hidden_nodegroups_field").val("create_nodegroup");
|
||||
$(".hidden_configure_field").val("create_nodegroup");
|
||||
var form = $(".hidden_nodegroups_field").closest("form");
|
||||
form.submit();
|
||||
});
|
||||
|
||||
|
||||
$(".hidden_nodegroups_field").val("");
|
||||
$(".hidden_configure_field").val("");
|
||||
|
||||
if ($(modal).find(".hidden_create_field").length > 0) {
|
||||
var form = $(".hidden_create_field").closest("form");
|
||||
var successful = false;
|
||||
form.submit(function (e) {
|
||||
var oldHref = $(".configure-clustertemplate-btn")[0].href;
|
||||
var plugin = $("#id_plugin_name option:selected").val();
|
||||
var version = $("#id_" + plugin + "_version option:selected").val();
|
||||
form.find(".close").click();
|
||||
$(".configure-clustertemplate-btn")[0].href = oldHref +
|
||||
"?plugin_name=" + encodeURIComponent(plugin) +
|
||||
"&hadoop_version=" + encodeURIComponent(version);
|
||||
$(".configure-clustertemplate-btn").click();
|
||||
$(".configure-clustertemplate-btn")[0].href = oldHref;
|
||||
return false;
|
||||
});
|
||||
$(".plugin_version_choice").closest(".control-group").hide();
|
||||
}
|
||||
|
||||
//display version for selected plugin
|
||||
$(document).on('change', '.plugin_name_choice', switch_versions);
|
||||
function switch_versions() {
|
||||
$(".plugin_version_choice").closest(".control-group").hide();
|
||||
var plugin = $(this);
|
||||
$("." + plugin.val() + "_version_choice").closest(".control-group").show();
|
||||
}
|
||||
$(".plugin_name_choice").change();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Cluster Template" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Create Cluster Template") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'horizon/common/_workflow.html' %}
|
||||
{% endblock %}<!DOCTYPE html>
|
|
@ -1,11 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Cluster Template" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Create Cluster Template") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'horizon/common/_workflow.html' %}
|
||||
{% endblock %}<!DOCTYPE html>
|
|
@ -1,15 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n sizeformat %}
|
||||
{% block title %}{% trans "Cluster Template Details" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Cluster Template Details") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Upload Template" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Upload Template") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'cluster_templates/_upload_file.html' %}
|
||||
{% endblock %}
|
|
@ -1,19 +0,0 @@
|
|||
<div class="well">
|
||||
<p>
|
||||
This Cluster will be started with:
|
||||
<br >
|
||||
<b>Plugin</b>: {{ plugin_name }}
|
||||
<br />
|
||||
<b>Hadoop version</b>: {{ hadoop_version }}
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
Cluster can be launched using existing Cluster Templates.
|
||||
</p>
|
||||
<p>
|
||||
The Cluster object should specify OpenStack Image to boot instances for Hadoop Cluster.
|
||||
</p>
|
||||
<p>
|
||||
User has to choose a keypair to have access to clusters instances.
|
||||
</p>
|
||||
</div>
|
|
@ -1,23 +0,0 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
|
||||
{% load url from future %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}create_cluster_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:shara:clusters:create' %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Launch Cluster" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" id="create_cluster_btn" type="submit" value="{% trans " Done" %}"/>
|
||||
<a href="{% url 'horizon:shara:clusters:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -1,3 +0,0 @@
|
|||
<p class="well">
|
||||
Select a plugin and Hadoop version for a new Cluster.
|
||||
</p>
|
|
@ -1,89 +0,0 @@
|
|||
{% load i18n sizeformat %}
|
||||
{% load url from future %}
|
||||
<h3>{% trans "Cluster Overview" %}</h3>
|
||||
<div class="status row-fluid detail">
|
||||
<dl>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ cluster.name }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ cluster.id }}</dd>
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ cluster.description|default:"None" }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ cluster.status }}</dd>
|
||||
</dl>
|
||||
|
||||
{% if cluster.error_description %}
|
||||
<h4>{% trans "Error Details" %}</h4>
|
||||
<p class="well">
|
||||
{{ cluster.error_description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<dl>
|
||||
<dt>{% trans "Plugin" %}</dt>
|
||||
<dd><a href="{% url 'horizon:sahara:plugins:details' cluster.plugin_name %}">{{ cluster.plugin_name }}</a></dd>
|
||||
<dt>{% trans "Hadoop Version" %}</dt>
|
||||
<dd>{{ cluster.hadoop_version }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Template" %}</dt>
|
||||
{% if cluster_template %}
|
||||
<dd><a href="{% url 'horizon:sahara:cluster_templates:details' cluster_template.id %}">{{ cluster_template.name }} </a></dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Template not specified" %}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Base Image" %}</dt>
|
||||
<dd>{{ base_image.name }}</dd>
|
||||
{% if network %}
|
||||
<dt>{% trans "Neutron Management Network" %}</dt>
|
||||
<dd>{{ network }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Keypair" %}</dt>
|
||||
<dd>{{ cluster.user_keypair_id }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Anti-affinity enabled for" %}</dt>
|
||||
{% if cluster.anti_affinity %}
|
||||
<dd>
|
||||
<ul>
|
||||
{% for process in cluster.anti_affinity %}
|
||||
<li>{{ process }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
{% else %}
|
||||
<h6>{% trans "no processes" %}</h6>
|
||||
{% endif %}
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{% trans "Node Configurations" %}</dt>
|
||||
{% if cluster.cluster_configs %}
|
||||
<dd>
|
||||
{% for service, service_conf in cluster.cluster_configs.items %}
|
||||
<h4>{{ service }}</h4>
|
||||
{% if service_conf %}
|
||||
<ul>
|
||||
{% for conf_name, conf_value in service_conf.items %}
|
||||
<li>{{ conf_name }}: {{ conf_value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h6>No configurations</h6>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Cluster configurations are not specified" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
{% for info_key, info_val in cluster.info.items %}
|
||||
<dt>{{ info_key }}</dt>
|
||||
{% for key, val in info_val.items %}
|
||||
<dd>{{ key }}: {% autoescape off %}{{ val }}{% endautoescape %}</dd>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</dl>
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
{% load i18n sizeformat %}
|
||||
<h3>{% trans "Cluster Instances" %}</h3>
|
||||
<div class="status row-fluid detail">
|
||||
{{ cluster_instances_table.render }}
|
||||
</div>
|
|
@ -1,63 +0,0 @@
|
|||
{% load i18n sizeformat %}
|
||||
|
||||
{% load url from future %}
|
||||
|
||||
|
||||
<h3>{% trans "Node Groups" %}</h3>
|
||||
<div class="status row-fluid detail">
|
||||
{% for node_group in cluster.node_groups %}
|
||||
<dl class="well">
|
||||
<h4>{% trans "Name" %}: {{ node_group.name }}</h4>
|
||||
<dt>{% trans "Number of Nodes" %}</dt>
|
||||
<dd>{{ node_group.count }}</dd>
|
||||
|
||||
<dt>{% trans "Flavor" %}</dt>
|
||||
<dd>{{ node_group.flavor_name|default:"Flavor is not specified" }}</dd>
|
||||
|
||||
{% if node_group.floating_ip_pool %}
|
||||
<dt>{% trans "Floating IP Pool" %}</dt>
|
||||
<dd>{{ node_group.floating_ip_pool }}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt>{% trans "Template" %}</dt>
|
||||
{% if node_group.node_group_template_id %}
|
||||
<dd><a href="{% url 'horizon:sahara:nodegroup_templates:details' node_group.node_group_template_id %}">{{ node_group.node_group_template.name }} </a></dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Template not specified" %}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt>{% trans "Node Processes" %}</dt>
|
||||
{% if node_group.node_processes %}
|
||||
<dd>
|
||||
<ul>
|
||||
{% for process in node_group.node_processes %}
|
||||
<li>{{ process }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Node processes are not specified" %}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt>{% trans "Node Configurations" %}</dt>
|
||||
{% if node_group.node_configs %}
|
||||
<dd>
|
||||
{% for service, service_conf in node_group.node_configs.items %}
|
||||
<h4>{{ service }}</h4>
|
||||
{% if service_conf %}
|
||||
<ul>
|
||||
{% for conf_name, conf_value in service_conf.items %}
|
||||
<li>{{ conf_name }}: {{ conf_value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h6>No configurations</h6>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "Node configurations are not specified" %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endfor %}
|
||||
</div>
|
|
@ -1,61 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Sahara" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Clusters") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="cluster_templates">
|
||||
{{ clusters_table.render }}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
addHorizonLoadEvent(function () {
|
||||
|
||||
horizon.modals.addModalInitFunction(function (modal) {
|
||||
if ($(modal).find(".nav-tabs").find("li").size() == 1) {
|
||||
// hide tab bar for plugin/version modal wizard
|
||||
$('div#modal_wrapper ul.nav-tabs').hide();
|
||||
}
|
||||
|
||||
$(".hidden_nodegroups_field").val("");
|
||||
$(".hidden_configure_field").val("");
|
||||
|
||||
lower_limit = 0;
|
||||
$(".count-field").change();
|
||||
|
||||
if ($(modal).find(".hidden_create_field").length > 0) {
|
||||
var form = $(".hidden_create_field").closest("form");
|
||||
var successful = false;
|
||||
form.submit(function (e) {
|
||||
var oldHref = $(".configure-cluster-btn")[0].href;
|
||||
var plugin = $("#id_plugin_name option:selected").val();
|
||||
var version = $("#id_" + plugin + "_version option:selected").val();
|
||||
form.find(".close").click();
|
||||
$(".configure-cluster-btn")[0].href = oldHref +
|
||||
"?plugin_name=" + encodeURIComponent(plugin) +
|
||||
"&hadoop_version=" + encodeURIComponent(version);
|
||||
$(".configure-cluster-btn").click();
|
||||
$(".configure-cluster-btn")[0].href = oldHref;
|
||||
return false;
|
||||
});
|
||||
$(".plugin_version_choice").closest(".control-group").hide();
|
||||
}
|
||||
|
||||
//display version for selected plugin
|
||||
$(document).on('change', '.plugin_name_choice', switch_versions);
|
||||
function switch_versions() {
|
||||
$(".plugin_version_choice").closest(".control-group").hide();
|
||||
var plugin = $(this);
|
||||
$("." + plugin.val() + "_version_choice").closest(".control-group").show();
|
||||
}
|
||||
$(".plugin_name_choice").change();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Launch Cluster" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Launch Cluster") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'horizon/common/_workflow.html' %}
|
||||
{% endblock %}<!DOCTYPE html>
|
|
@ -1,11 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Launch Cluster" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Sahara - Launch Cluster") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'horizon/common/_workflow.html' %}
|
||||
{% endblock %}<!DOCTYPE html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue