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
|
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
|
Sahara project: https://github.com/openstack/sahara
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
pbr>=0.6,!=0.7,<1.0
|
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