Adding Job Binaries panel for Sahara
The Job Binaries panel allows for creating/uploading files that will serve as executables or libraries for Elastic Data Processing jobs. This code was originally from: https://github.com/openstack/sahara-dashboard Change-Id: I4e7b265a7d3292d7cec395bf2ff11fd546f06360 Partial-Implements: blueprint merge-sahara-dashboard Co-Authored-By: Nikita Konovalov <nkonovalov@mirantis.com> Co-Authored-By: Dmitry Mescheryakov <dmescheryakov@mirantis.com>
This commit is contained in:
parent
991882ca4a
commit
f25628d91c
@ -65,7 +65,8 @@ class DataProcessingPanels(horizon.PanelGroup):
|
|||||||
'data_processing.nodegroup_templates',
|
'data_processing.nodegroup_templates',
|
||||||
'data_processing.cluster_templates',
|
'data_processing.cluster_templates',
|
||||||
'data_processing.clusters',
|
'data_processing.clusters',
|
||||||
'data_processing.data_sources', )
|
'data_processing.data_sources',
|
||||||
|
'data_processing.job_binaries', )
|
||||||
|
|
||||||
|
|
||||||
class Project(horizon.Dashboard):
|
class Project(horizon.Dashboard):
|
||||||
|
@ -0,0 +1,197 @@
|
|||||||
|
# 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 import util
|
||||||
|
from django.forms import widgets
|
||||||
|
from django import template
|
||||||
|
from django.template import defaultfilters
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
from openstack_dashboard.api import sahara as saharaclient
|
||||||
|
|
||||||
|
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 />' % util.flatatt(final_attrs)))
|
||||||
|
return mark_safe(output)
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryCreateForm(forms.SelfHandlingForm):
|
||||||
|
NEW_SCRIPT = "%%%NEWSCRIPT%%%"
|
||||||
|
UPLOAD_BIN = "%%%UPLOADFILE%%%"
|
||||||
|
|
||||||
|
job_binary_name = forms.CharField(label=_("Name"))
|
||||||
|
|
||||||
|
job_binary_type = forms.ChoiceField(label=_("Storage type"))
|
||||||
|
|
||||||
|
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 = ("project/data_processing.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):
|
||||||
|
try:
|
||||||
|
job_binaries = saharaclient.job_binary_internal_list(request)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Failed to get list of internal binaries."))
|
||||||
|
job_binaries = []
|
||||||
|
|
||||||
|
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:
|
||||||
|
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)
|
||||||
|
|
||||||
|
saharaclient.job_binary_create(
|
||||||
|
request,
|
||||||
|
context["job_binary_name"],
|
||||||
|
bin_url,
|
||||||
|
context["job_binary_description"],
|
||||||
|
extra)
|
||||||
|
messages.success(request, "Successfully created job binary")
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Unable to create job binary"))
|
||||||
|
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 += defaultfilters.linebreaks(force_unicode(self.help_text))
|
||||||
|
return defaultfilters.safe(text)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
name = _("Create Job Binary")
|
||||||
|
help_text_template = ("project/data_processing.job_binaries/"
|
||||||
|
"_create_job_binary_help.html")
|
||||||
|
|
||||||
|
def handle_internal(self, request, context):
|
||||||
|
result = ""
|
||||||
|
|
||||||
|
bin_id = context["job_binary_internal"]
|
||||||
|
if(bin_id == self.UPLOAD_BIN):
|
||||||
|
try:
|
||||||
|
result = saharaclient.job_binary_internal_create(
|
||||||
|
request,
|
||||||
|
self.get_unique_binary_name(
|
||||||
|
request, request.FILES["job_binary_file"].name),
|
||||||
|
request.FILES["job_binary_file"].read())
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Unable to upload job binary"))
|
||||||
|
return None
|
||||||
|
elif(bin_id == self.NEW_SCRIPT):
|
||||||
|
try:
|
||||||
|
result = saharaclient.job_binary_internal_create(
|
||||||
|
request,
|
||||||
|
self.get_unique_binary_name(
|
||||||
|
request, context["job_binary_script_name"]),
|
||||||
|
context["job_binary_script"])
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Unable to create job binary"))
|
||||||
|
return None
|
||||||
|
|
||||||
|
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):
|
||||||
|
try:
|
||||||
|
internals = saharaclient.job_binary_internal_list(request)
|
||||||
|
except Exception:
|
||||||
|
internals = []
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Failed to fetch internal binary list"))
|
||||||
|
names = [internal.name for internal in internals]
|
||||||
|
if base_name in names:
|
||||||
|
return "%s_%s" % (base_name, uuid.uuid1())
|
||||||
|
return base_name
|
@ -0,0 +1,27 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.project import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinariesPanel(horizon.Panel):
|
||||||
|
name = _("Job Binaries")
|
||||||
|
slug = 'data_processing.job_binaries'
|
||||||
|
permissions = ('openstack.services.data_processing',)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Project.register(JobBinariesPanel)
|
@ -0,0 +1,79 @@
|
|||||||
|
# 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 openstack_dashboard.api import sahara as saharaclient
|
||||||
|
|
||||||
|
from saharaclient.api import base as api_base
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateJobBinary(tables.LinkAction):
|
||||||
|
name = "create job binary"
|
||||||
|
verbose_name = _("Create Job Binary")
|
||||||
|
url = "horizon:project:data_processing.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):
|
||||||
|
jb = saharaclient.job_binary_get(request, obj_id)
|
||||||
|
(jb_type, jb_internal_id) = jb.url.split("://")
|
||||||
|
if jb_type == "internal-db":
|
||||||
|
try:
|
||||||
|
saharaclient.job_binary_internal_delete(request,
|
||||||
|
jb_internal_id)
|
||||||
|
except api_base.APIException:
|
||||||
|
# nothing to do for job-binary-internal if
|
||||||
|
# it does not exist.
|
||||||
|
pass
|
||||||
|
|
||||||
|
saharaclient.job_binary_delete(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadJobBinary(tables.LinkAction):
|
||||||
|
name = "download job binary"
|
||||||
|
verbose_name = _("Download Job Binary")
|
||||||
|
url = "horizon:project:data_processing.job_binaries:download"
|
||||||
|
classes = ("btn-edit")
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinariesTable(tables.DataTable):
|
||||||
|
name = tables.Column("name",
|
||||||
|
verbose_name=_("Name"),
|
||||||
|
link=("horizon:project:data_processing.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)
|
@ -0,0 +1,45 @@
|
|||||||
|
# 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 exceptions
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
from openstack_dashboard.api import sahara as saharaclient
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryDetailsTab(tabs.Tab):
|
||||||
|
name = _("General Info")
|
||||||
|
slug = "job_binaries_details_tab"
|
||||||
|
template_name = ("project/data_processing.job_binaries/_details.html")
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
job_binary_id = self.tab_group.kwargs['job_binary_id']
|
||||||
|
try:
|
||||||
|
job_binary = saharaclient.job_binary_get(request, job_binary_id)
|
||||||
|
except Exception:
|
||||||
|
job_binary = {}
|
||||||
|
exceptions.handle(request,
|
||||||
|
_("Unable to fetch job binary."))
|
||||||
|
return {"job_binary": job_binary}
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryDetailsTabs(tabs.TabGroup):
|
||||||
|
slug = "job_binary_details"
|
||||||
|
tabs = (JobBinaryDetailsTab,)
|
||||||
|
sticky = True
|
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_id %}create-job-binary{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:project:data_processing.job_binaries:create-job-binary' %}{% endblock %}
|
||||||
|
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-header %}{% trans "Create Job Binary" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="form-help-block">
|
||||||
|
{{ form.get_help_text }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" id="upload_file_btn" type="submit" value="{% trans "Create" %}"/>
|
||||||
|
<a href="{% url 'horizon:project:data_processing.job_binaries:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,32 @@
|
|||||||
|
{% load i18n horizon %}
|
||||||
|
<div class="well">
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}<b>Important</b>: The name that you give your job binary will be the name used in your job execution.
|
||||||
|
If your binary requires a particular name or extension (ie: ".jar"), be sure to include it here.{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}Select the storage type for your job binary.{% endblocktrans %}
|
||||||
|
<ul>
|
||||||
|
<li>{% blocktrans %}Data Processing internal database{% endblocktrans %}</li>
|
||||||
|
<li>{% blocktrans %}Swift{% endblocktrans %}</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}For Data Processing internal job binaries, you may choose from the following:{% endblocktrans %}
|
||||||
|
<ul>
|
||||||
|
<li>{% blocktrans %}Choose an existing file{% endblocktrans %}</li>
|
||||||
|
<li>{% blocktrans %}Upload a new file{% endblocktrans %}</li>
|
||||||
|
<li>{% blocktrans %}Create a script to be uploaded dynamically{% endblocktrans %}</ul>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}For Object Store job binaries, you must:{% endblocktrans %}
|
||||||
|
<ul>
|
||||||
|
<li>{% blocktrans %}Enter the URL for the file{% endblocktrans %}</li>
|
||||||
|
<li>{% blocktrans %}Enter the username and password required to access that file{% endblocktrans %}</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}You may also enter an optional description for your job binary.{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
</div>
|
@ -0,0 +1,19 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<h3>{% trans "Job Binary Overview" %}</h3>
|
||||||
|
<div class="status row-fluid detail">
|
||||||
|
<dl>
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ job_binary.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ job_binary.id }}</dd>
|
||||||
|
<dt>{% trans "URL" %}</dt>
|
||||||
|
<dd>{{ job_binary.url }}</dd>
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ job_binary.description|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Project id" %}</dt>
|
||||||
|
<dd>{{ job_binary.tenant_id }}</dd>
|
||||||
|
<dt>{% trans "Create time" %}</dt>
|
||||||
|
<dd>{{ job_binary.created_at }}</dd>
|
||||||
|
</dl>
|
||||||
|
<a href="{% url 'horizon:project:data_processing.job_binaries:download' job_binary.id %}">{% trans "Download job binary" %}</a>
|
||||||
|
</div>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Create Job Binary" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Create Job Binary") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'project/data_processing.job_binaries/_create.html' %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Job Binary Details" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Job Binary Details") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Data Processing" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Job Binaries") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<style type="text/css">
|
||||||
|
#id_job_binary_url {
|
||||||
|
width: 200px !important; }
|
||||||
|
.form-help-block {
|
||||||
|
float: left;
|
||||||
|
text-align: left;
|
||||||
|
width: 300px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="job_binaries">
|
||||||
|
{{ job_binaries_table.render }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "project/data_processing.job_binaries/job_binaries_form_script.html" %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
addHorizonLoadEvent(function () {
|
||||||
|
horizon.modals.addModalInitFunction(function (modal) {
|
||||||
|
hide_extra_fields();
|
||||||
|
function hide_extra_fields() {
|
||||||
|
$("[name=job_binary_username]").closest(".control-group").hide();
|
||||||
|
$("[name=job_binary_password]").closest(".control-group").hide();
|
||||||
|
$("[name=job_binary_file]").closest(".control-group").hide();
|
||||||
|
$("[name=job_binary_url]").closest(".control-group").hide();
|
||||||
|
$("[name=job_binary_internal]").closest(".control-group").hide();
|
||||||
|
}
|
||||||
|
$("#id_job_binary_type").change(function() {
|
||||||
|
var label = $("#id_job_binary_url_label");
|
||||||
|
var bin_file = $("[name=job_binary_file]").closest(".control-group");
|
||||||
|
var bin_choice = $("[name=job_binary_internal]").closest(".control-group");
|
||||||
|
var bin_url = $("[name=job_binary_url]").closest(".control-group");
|
||||||
|
var username = $("[name=job_binary_username]").closest(".control-group");
|
||||||
|
var password = $("[name=job_binary_password]").closest(".control-group");
|
||||||
|
var script_name = $("[name=job_binary_script_name]").closest(".control-group");
|
||||||
|
var script_text = $("[name=job_binary_script]").closest(".control-group");
|
||||||
|
switch($(this).val()) {
|
||||||
|
case "internal-db":
|
||||||
|
label.html("internal-db://");
|
||||||
|
username.hide();
|
||||||
|
password.hide();
|
||||||
|
bin_file.show();
|
||||||
|
bin_choice.show();
|
||||||
|
bin_url.hide();
|
||||||
|
script_name.hide();
|
||||||
|
script_text.hide();
|
||||||
|
break;
|
||||||
|
case "swift":
|
||||||
|
username.show();
|
||||||
|
password.show();
|
||||||
|
bin_file.hide();
|
||||||
|
bin_choice.hide();
|
||||||
|
bin_url.show();
|
||||||
|
label.html("swift://");
|
||||||
|
script_name.hide();
|
||||||
|
script_text.hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#id_job_binary_type").change();
|
||||||
|
|
||||||
|
$("[name=job_binary_internal]").change(function() {
|
||||||
|
var bin_file = $("[name=job_binary_file]").closest(".control-group");
|
||||||
|
var bin_choice = $("[name=job_binary_internal]").closest(".control-group");
|
||||||
|
var bin_url = $("[name=job_binary_url]").closest(".control-group");
|
||||||
|
var script_name = $("[name=job_binary_script_name]").closest(".control-group");
|
||||||
|
var script_text = $("[name=job_binary_script]").closest(".control-group");
|
||||||
|
switch($(this).val()) {
|
||||||
|
case "%%%NEWSCRIPT%%%":
|
||||||
|
bin_file.hide();
|
||||||
|
script_name.show();
|
||||||
|
script_text.show();
|
||||||
|
break;
|
||||||
|
case "%%%UPLOADFILE%%%":
|
||||||
|
bin_file.show();
|
||||||
|
script_name.hide();
|
||||||
|
script_text.hide();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bin_file.hide();
|
||||||
|
script_name.hide();
|
||||||
|
script_text.hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#job_binary_internal").change();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
@ -0,0 +1,80 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django import http
|
||||||
|
|
||||||
|
from mox import IsA # noqa
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard.test import helpers as test
|
||||||
|
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:project:data_processing.job_binaries:index')
|
||||||
|
DETAILS_URL = reverse(
|
||||||
|
'horizon:project:data_processing.job_binaries:details', args=['id'])
|
||||||
|
|
||||||
|
|
||||||
|
class DataProcessingJobBinaryTests(test.TestCase):
|
||||||
|
@test.create_stubs({api.sahara: ('job_binary_list',)})
|
||||||
|
def test_index(self):
|
||||||
|
api.sahara.job_binary_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.job_binaries.list())
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
res = self.client.get(INDEX_URL)
|
||||||
|
self.assertTemplateUsed(res,
|
||||||
|
'project/data_processing.job_binaries/job_binaries.html')
|
||||||
|
self.assertContains(res, 'Job Binaries')
|
||||||
|
self.assertContains(res, 'Name')
|
||||||
|
self.assertContains(res, 'example.pig')
|
||||||
|
|
||||||
|
@test.create_stubs({api.sahara: ('job_binary_get',)})
|
||||||
|
def test_details(self):
|
||||||
|
api.sahara.job_binary_get(IsA(http.HttpRequest), IsA(unicode)) \
|
||||||
|
.AndReturn(self.job_binaries.list()[0])
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
res = self.client.get(DETAILS_URL)
|
||||||
|
self.assertTemplateUsed(res,
|
||||||
|
'project/data_processing.job_binaries/details.html')
|
||||||
|
self.assertContains(res, 'Job Binary Details')
|
||||||
|
|
||||||
|
@test.create_stubs({api.sahara: ('job_binary_list',
|
||||||
|
'job_binary_get',
|
||||||
|
'job_binary_internal_delete',
|
||||||
|
'job_binary_delete',)})
|
||||||
|
def test_delete(self):
|
||||||
|
jb_list = (api.sahara.job_binary_list(IsA(http.HttpRequest))
|
||||||
|
.AndReturn(self.job_binaries.list()))
|
||||||
|
api.sahara.job_binary_get(IsA(http.HttpRequest), IsA(unicode)) \
|
||||||
|
.AndReturn(self.job_binaries.list()[0])
|
||||||
|
api.sahara.job_binary_delete(IsA(http.HttpRequest), jb_list[0].id)
|
||||||
|
int_id = jb_list[0].url.split("//")[1]
|
||||||
|
api.sahara.job_binary_internal_delete(IsA(http.HttpRequest), int_id)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
form_data = {"action": "job_binaries__delete__%s" % jb_list[0].id}
|
||||||
|
res = self.client.post(INDEX_URL, form_data)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
@test.create_stubs({api.sahara: ('job_binary_get',
|
||||||
|
'job_binary_get_file')})
|
||||||
|
def test_download(self):
|
||||||
|
jb = api.sahara.job_binary_get(IsA(http.HttpRequest), IsA(unicode)) \
|
||||||
|
.AndReturn(self.job_binaries.list()[0])
|
||||||
|
api.sahara.job_binary_get_file(IsA(http.HttpRequest), jb.id) \
|
||||||
|
.AndReturn("TEST FILE CONTENT")
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
context = {'job_binary_id': jb.id}
|
||||||
|
url = reverse('horizon:project:data_processing.job_binaries:download',
|
||||||
|
kwargs={'job_binary_id': jb.id})
|
||||||
|
res = self.client.get(url, context)
|
||||||
|
self.assertTrue(res.has_header('content-disposition'))
|
@ -0,0 +1,35 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
from django.conf.urls import patterns # noqa
|
||||||
|
from django.conf.urls import url # noqa
|
||||||
|
|
||||||
|
import openstack_dashboard.dashboards.project.data_processing. \
|
||||||
|
job_binaries.views as views
|
||||||
|
|
||||||
|
|
||||||
|
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'))
|
@ -0,0 +1,93 @@
|
|||||||
|
# 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 import defaultfilters
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.views import generic
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
from openstack_dashboard.api import sahara as saharaclient
|
||||||
|
|
||||||
|
import openstack_dashboard.dashboards.project.data_processing. \
|
||||||
|
job_binaries.forms as job_binary_forms
|
||||||
|
from openstack_dashboard.dashboards.project.data_processing.job_binaries \
|
||||||
|
import tables as jb_tables
|
||||||
|
import openstack_dashboard.dashboards.project.data_processing.job_binaries. \
|
||||||
|
tabs as _tabs
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinariesView(tables.DataTableView):
|
||||||
|
table_class = jb_tables.JobBinariesTable
|
||||||
|
template_name = 'project/data_processing.job_binaries/job_binaries.html'
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
job_binaries = saharaclient.job_binary_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
job_binaries = []
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_("Unable to fetch job binary list."))
|
||||||
|
return job_binaries
|
||||||
|
|
||||||
|
|
||||||
|
class CreateJobBinaryView(forms.ModalFormView):
|
||||||
|
form_class = job_binary_forms.JobBinaryCreateForm
|
||||||
|
success_url = reverse_lazy(
|
||||||
|
'horizon:project:data_processing.job_binaries:index')
|
||||||
|
classes = ("ajax-modal")
|
||||||
|
template_name = "project/data_processing.job_binaries/create.html"
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryDetailsView(tabs.TabView):
|
||||||
|
tab_group_class = _tabs.JobBinaryDetailsTabs
|
||||||
|
template_name = 'project/data_processing.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(generic.View):
|
||||||
|
def get(self, request, job_binary_id=None):
|
||||||
|
try:
|
||||||
|
jb = saharaclient.job_binary_get(request, job_binary_id)
|
||||||
|
data = saharaclient.job_binary_get_file(request, job_binary_id)
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse(
|
||||||
|
'horizon:project:data_processing.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' % defaultfilters.slugify(jb.name)
|
||||||
|
response.write(data)
|
||||||
|
response['Content-Length'] = str(len(data))
|
||||||
|
return response
|
@ -15,6 +15,7 @@ from openstack_dashboard.test.test_data import utils
|
|||||||
from saharaclient.api import cluster_templates
|
from saharaclient.api import cluster_templates
|
||||||
from saharaclient.api import clusters
|
from saharaclient.api import clusters
|
||||||
from saharaclient.api import data_sources
|
from saharaclient.api import data_sources
|
||||||
|
from saharaclient.api import job_binaries
|
||||||
from saharaclient.api import node_group_templates
|
from saharaclient.api import node_group_templates
|
||||||
from saharaclient.api import plugins
|
from saharaclient.api import plugins
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ def data(TEST):
|
|||||||
TEST.cluster_templates = utils.TestDataContainer()
|
TEST.cluster_templates = utils.TestDataContainer()
|
||||||
TEST.clusters = utils.TestDataContainer()
|
TEST.clusters = utils.TestDataContainer()
|
||||||
TEST.data_sources = utils.TestDataContainer()
|
TEST.data_sources = utils.TestDataContainer()
|
||||||
|
TEST.job_binaries = utils.TestDataContainer()
|
||||||
|
|
||||||
plugin1_dict = {
|
plugin1_dict = {
|
||||||
"description": "vanilla plugin",
|
"description": "vanilla plugin",
|
||||||
@ -261,3 +263,18 @@ def data(TEST):
|
|||||||
data_sources.DataSourceManager(None), data_source2_dict)
|
data_sources.DataSourceManager(None), data_source2_dict)
|
||||||
TEST.data_sources.add(data_source1)
|
TEST.data_sources.add(data_source1)
|
||||||
TEST.data_sources.add(data_source2)
|
TEST.data_sources.add(data_source2)
|
||||||
|
|
||||||
|
#Job Binaries
|
||||||
|
job_binary1_dict = {
|
||||||
|
"created_at": "2014-06-05 18:15:15.581285",
|
||||||
|
"description": "",
|
||||||
|
"id": "3f3a07ac-7d6f-49e8-8669-40b25ee891b7",
|
||||||
|
"name": "example.pig",
|
||||||
|
"tenant_id": "429ad8447c2d47bc8e0382d244e1d1df",
|
||||||
|
"updated_at": None,
|
||||||
|
"url": "internal-db://80121dea-f8bd-4ad3-bcc7-096f4bfc722d"
|
||||||
|
}
|
||||||
|
|
||||||
|
job_binary1 = job_binaries.JobBinaries(
|
||||||
|
job_binaries.JobBinariesManager(None), job_binary1_dict)
|
||||||
|
TEST.job_binaries.add(job_binary1)
|
||||||
|
Loading…
Reference in New Issue
Block a user