Adds EDP support in the UI for job execution
First pass at job execution in the UI. Job binaries tab has been added, still needs work to handle internal and external sources as well as overall refinement of controls. Now includes job_binaries as a form rather than a workflow and forces a unique name for binary-internal uploads. Implements: blueprint edp-savanna-dashboard-ui Change-Id: Id32f7c5d5458918bd832070c53271c042d886f86
This commit is contained in:
parent
87e1e220f1
commit
d2060199b2
@ -78,6 +78,7 @@ class ResourceManager(object):
|
|||||||
resp = self.api.client.put(url, json.dumps(data))
|
resp = self.api.client.put(url, json.dumps(data))
|
||||||
if resp.status_code != 202:
|
if resp.status_code != 202:
|
||||||
self._raise_api_exception(resp)
|
self._raise_api_exception(resp)
|
||||||
|
return get_json(resp)
|
||||||
|
|
||||||
def _list(self, url, response_key):
|
def _list(self, url, response_key):
|
||||||
resp = self.api.client.get(url)
|
resp = self.api.client.get(url)
|
||||||
|
@ -22,6 +22,9 @@ from savannadashboard.api import clusters
|
|||||||
from savannadashboard.api import data_sources
|
from savannadashboard.api import data_sources
|
||||||
from savannadashboard.api import httpclient
|
from savannadashboard.api import httpclient
|
||||||
from savannadashboard.api import images
|
from savannadashboard.api import images
|
||||||
|
from savannadashboard.api import job_binaries
|
||||||
|
from savannadashboard.api import job_binaries_internal
|
||||||
|
from savannadashboard.api import job_executions
|
||||||
from savannadashboard.api import job_origins
|
from savannadashboard.api import job_origins
|
||||||
from savannadashboard.api import jobs
|
from savannadashboard.api import jobs
|
||||||
from savannadashboard.api import node_group_templates
|
from savannadashboard.api import node_group_templates
|
||||||
@ -77,3 +80,7 @@ class Client(object):
|
|||||||
self.jobs = jobs.JobManager(self)
|
self.jobs = jobs.JobManager(self)
|
||||||
self.job_origins = job_origins.JobOriginManager(self)
|
self.job_origins = job_origins.JobOriginManager(self)
|
||||||
self.data_sources = data_sources.DataSourceManager(self)
|
self.data_sources = data_sources.DataSourceManager(self)
|
||||||
|
self.job_executions = job_executions.JobExecutionManager(self)
|
||||||
|
self.job_binaries = job_binaries.JobBinaryManager(self)
|
||||||
|
self.job_binaries_internal =\
|
||||||
|
job_binaries_internal.JobBinaryInternalManager(self)
|
||||||
|
47
savannadashboard/api/job_binaries.py
Normal file
47
savannadashboard/api/job_binaries.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import base
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinary(base.Resource):
|
||||||
|
resource_name = 'Job Binary'
|
||||||
|
defaults = {}
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryManager(base.ResourceManager):
|
||||||
|
resource_class = JobBinary
|
||||||
|
|
||||||
|
def create(self, name, url, description, extra):
|
||||||
|
data = {
|
||||||
|
"name": name,
|
||||||
|
"url": url,
|
||||||
|
"description": description,
|
||||||
|
"extra": extra
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._create('/job-binaries', data)
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return self._list('/job-binaries', 'binaries')
|
||||||
|
|
||||||
|
def get(self, job_binary_id):
|
||||||
|
return self._get('/job-binaries/%s' % job_binary_id,
|
||||||
|
'resource')
|
||||||
|
|
||||||
|
def delete(self, job_binary_id):
|
||||||
|
self._delete('/job-binaries/%s' % job_binary_id)
|
42
savannadashboard/api/job_binaries_internal.py
Normal file
42
savannadashboard/api/job_binaries_internal.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import base
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryInternal(base.Resource):
|
||||||
|
resource_name = 'Job Binary Internal'
|
||||||
|
defaults = {}
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryInternalManager(base.ResourceManager):
|
||||||
|
resource_class = JobBinaryInternal
|
||||||
|
|
||||||
|
def create(self, name, data):
|
||||||
|
resp = self.api.client.put('/job-binary-internals/%s' % name, data)
|
||||||
|
if resp.status_code != 202:
|
||||||
|
self._raise_api_exception(resp)
|
||||||
|
return resp.json()
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return self._list('/job-binary-internals', 'binaries')
|
||||||
|
|
||||||
|
def get(self, job_binary_id):
|
||||||
|
return self._get('/job-binary-internals/%s' % job_binary_id,
|
||||||
|
'resource')
|
||||||
|
|
||||||
|
def delete(self, job_binary_id):
|
||||||
|
self._delete('/job-binary-internals/%s' % job_binary_id)
|
36
savannadashboard/api/job_executions.py
Normal file
36
savannadashboard/api/job_executions.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import base
|
||||||
|
|
||||||
|
|
||||||
|
class JobExecution(base.Resource):
|
||||||
|
resource_name = 'JobExecution'
|
||||||
|
|
||||||
|
|
||||||
|
class JobExecutionManager(base.ResourceManager):
|
||||||
|
resource_class = JobExecution
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return self._list('/job-executions', 'job_executions')
|
||||||
|
|
||||||
|
def get(self, obj_id):
|
||||||
|
return self._get('/job-executions/%s' % obj_id,
|
||||||
|
'resource')
|
||||||
|
|
||||||
|
def delete(self, obj_id):
|
||||||
|
self._delete('/job-executions/%s' % obj_id)
|
@ -26,17 +26,13 @@ class JobOrigin(base.Resource):
|
|||||||
class JobOriginManager(base.ResourceManager):
|
class JobOriginManager(base.ResourceManager):
|
||||||
resource_class = JobOrigin
|
resource_class = JobOrigin
|
||||||
|
|
||||||
def create(self, name, storage_type, username, password,
|
def create(self, name, mains, libs, description):
|
||||||
location, description):
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'credentials': {'user': username,
|
|
||||||
'password': password
|
|
||||||
},
|
|
||||||
'name': name,
|
'name': name,
|
||||||
'description': description,
|
'description': description,
|
||||||
'storage_type': storage_type,
|
'mains': mains,
|
||||||
'url': location
|
'libs': libs # TODO(croberts)fix when api is ready
|
||||||
}
|
}
|
||||||
self._create('/job-origins', data)
|
self._create('/job-origins', data)
|
||||||
|
|
||||||
|
@ -48,3 +48,14 @@ class JobManager(base.ResourceManager):
|
|||||||
|
|
||||||
def delete(self, job_id):
|
def delete(self, job_id):
|
||||||
self._delete('/jobs/%s' % job_id)
|
self._delete('/jobs/%s' % job_id)
|
||||||
|
|
||||||
|
def launch(self, job_id, cluster_id, input_id, output_id, configs):
|
||||||
|
url = "/jobs/%s/execute" % job_id
|
||||||
|
data = {
|
||||||
|
"input_id": input_id,
|
||||||
|
"output_id": output_id,
|
||||||
|
"cluster_id": cluster_id,
|
||||||
|
"job_configs": configs
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._create(url, data)
|
||||||
|
@ -31,8 +31,10 @@ class SavannaDashboard(horizon.Dashboard):
|
|||||||
panels = ('clusters',
|
panels = ('clusters',
|
||||||
'cluster_templates',
|
'cluster_templates',
|
||||||
'nodegroup_templates',
|
'nodegroup_templates',
|
||||||
|
'job_executions',
|
||||||
'jobs',
|
'jobs',
|
||||||
'job_origins',
|
'job_origins',
|
||||||
|
'job_binaries',
|
||||||
'data_sources',
|
'data_sources',
|
||||||
'image_registry',
|
'image_registry',
|
||||||
'plugins')
|
'plugins')
|
||||||
|
@ -39,9 +39,6 @@ class DataSourcesView(tables.DataTableView):
|
|||||||
data_sources = savanna.data_sources.list()
|
data_sources = savanna.data_sources.list()
|
||||||
return data_sources
|
return data_sources
|
||||||
|
|
||||||
class FakeDataSource(object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CreateDataSourceView(workflows.WorkflowView):
|
class CreateDataSourceView(workflows.WorkflowView):
|
||||||
workflow_class = create_flow.CreateDataSource
|
workflow_class = create_flow.CreateDataSource
|
||||||
|
@ -62,7 +62,6 @@ class GeneralConfigAction(workflows.Action):
|
|||||||
|
|
||||||
class GeneralConfig(workflows.Step):
|
class GeneralConfig(workflows.Step):
|
||||||
action_class = GeneralConfigAction
|
action_class = GeneralConfigAction
|
||||||
contributes = ("hidden_configure_field", )
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
def contribute(self, data, context):
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
|
0
savannadashboard/job_binaries/__init__.py
Normal file
0
savannadashboard/job_binaries/__init__.py
Normal file
154
savannadashboard/job_binaries/forms.py
Normal file
154
savannadashboard/job_binaries/forms.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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.forms.util import flatatt
|
||||||
|
from django.forms import widgets
|
||||||
|
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
|
import savannadashboard.api.base as api_base
|
||||||
|
from savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
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,
|
||||||
|
"savanna-db://",
|
||||||
|
('<input%s />' % flatatt(final_attrs)))
|
||||||
|
return mark_safe(output)
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryCreateForm(forms.SelfHandlingForm):
|
||||||
|
job_binary_name = forms.CharField(label=_("Name"),
|
||||||
|
required=True)
|
||||||
|
|
||||||
|
job_binary_type = forms.ChoiceField(label=_("Type"),
|
||||||
|
required=True)
|
||||||
|
|
||||||
|
job_binary_url = forms.CharField(label=_("URL"),
|
||||||
|
required=False,
|
||||||
|
widget=LabeledInput())
|
||||||
|
job_binary_savanna_internal = forms.ChoiceField(label=_("Savanna binary"),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
job_binary_file = forms.FileField(label=_("Upload File"),
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(JobBinaryCreateForm, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
self.fields["job_binary_type"].choices =\
|
||||||
|
[("savanna-db", "Savanna internal database"),
|
||||||
|
("swift-internal", "Swift internal"),
|
||||||
|
("swift-external", "Swift external")]
|
||||||
|
|
||||||
|
self.fields["job_binary_savanna_internal"].choices =\
|
||||||
|
self.populate_job_binary_savanna_internal_choices(request)
|
||||||
|
|
||||||
|
def populate_job_binary_savanna_internal_choices(self, request):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
job_binaries = savanna.job_binaries_internal.list()
|
||||||
|
|
||||||
|
choices = [(job_binary.id, job_binary.name)
|
||||||
|
for job_binary in job_binaries]
|
||||||
|
choices.insert(0, ('', 'Upload a new file'))
|
||||||
|
|
||||||
|
return choices
|
||||||
|
|
||||||
|
def handle(self, request, context):
|
||||||
|
try:
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
extra = {}
|
||||||
|
bin_url = "%s://%s" % (context["job_binary_type"],
|
||||||
|
context["job_binary_url"])
|
||||||
|
if(context["job_binary_type"] == "savanna-db"):
|
||||||
|
bin_url = self.handle_savanna(request, context)
|
||||||
|
if(context["job_binary_type"] == "swift-internal"):
|
||||||
|
extra = self.handle_swift_internal(request, context)
|
||||||
|
|
||||||
|
savanna.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 True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
name = _("Create Job Binary")
|
||||||
|
help_text_template = \
|
||||||
|
("job_binaries/_create_job_binary_help.html")
|
||||||
|
|
||||||
|
def handle_savanna(self, request, context):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
|
||||||
|
bin_id = context["job_binary_savanna_internal"]
|
||||||
|
if(bin_id == ""):
|
||||||
|
result = savanna.job_binaries_internal.create(
|
||||||
|
self.get_unique_binary_name(
|
||||||
|
request, request.FILES["job_binary_file"].name),
|
||||||
|
request.FILES["job_binary_file"].read())
|
||||||
|
bin_id = result["resource"]["id"]
|
||||||
|
|
||||||
|
return "savanna-db://%s" % bin_id
|
||||||
|
|
||||||
|
def handle_swift_internal(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):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
internals = savanna.job_binaries_internal.list()
|
||||||
|
names = [internal.name for internal in internals]
|
||||||
|
if base_name in names:
|
||||||
|
return "%s_%s" % (base_name, uuid.uuid1())
|
||||||
|
return base_name
|
30
savannadashboard/job_binaries/panel.py
Normal file
30
savannadashboard/job_binaries/panel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinariesPanel(horizon.Panel):
|
||||||
|
name = _("Job Binaries")
|
||||||
|
slug = 'job_binaries'
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.SavannaDashboard.register(JobBinariesPanel)
|
63
savannadashboard/job_binaries/tables.py
Normal file
63
savannadashboard/job_binaries/tables.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateJobBinary(tables.LinkAction):
|
||||||
|
name = "create job binary"
|
||||||
|
verbose_name = _("Create Job Binary")
|
||||||
|
url = "horizon:savanna: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):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
savanna.job_binaries.delete(obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinariesTable(tables.DataTable):
|
||||||
|
name = tables.Column("name",
|
||||||
|
verbose_name=_("Name"),
|
||||||
|
link=("horizon:savanna: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,)
|
44
savannadashboard/job_binaries/tabs.py
Normal file
44
savannadashboard/job_binaries/tabs.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
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']
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
job_binary = savanna.job_binaries.get(job_binary_id)
|
||||||
|
return {"job_binary": job_binary}
|
||||||
|
|
||||||
|
|
||||||
|
class JobBinaryDetailsTabs(tabs.TabGroup):
|
||||||
|
slug = "job_binary_details"
|
||||||
|
tabs = (GeneralTab,)
|
||||||
|
sticky = True
|
34
savannadashboard/job_binaries/urls.py
Normal file
34
savannadashboard/job_binaries/urls.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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.conf.urls.defaults import patterns
|
||||||
|
from django.conf.urls.defaults import url
|
||||||
|
|
||||||
|
import savannadashboard.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'))
|
63
savannadashboard/job_binaries/views.py
Normal file
63
savannadashboard/job_binaries/views.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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_lazy
|
||||||
|
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
from savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
import savannadashboard.job_binaries.forms as job_binary_forms
|
||||||
|
from savannadashboard.job_binaries.tables import JobBinariesTable
|
||||||
|
import savannadashboard.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):
|
||||||
|
savanna = savannaclient.Client(self.request)
|
||||||
|
job_binaries = savanna.job_binaries.list()
|
||||||
|
return job_binaries
|
||||||
|
|
||||||
|
|
||||||
|
class CreateJobBinaryView(forms.ModalFormView):
|
||||||
|
form_class = job_binary_forms.JobBinaryCreateForm
|
||||||
|
success_url = reverse_lazy('horizon:savanna: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
|
0
savannadashboard/job_executions/__init__.py
Normal file
0
savannadashboard/job_executions/__init__.py
Normal file
30
savannadashboard/job_executions/panel.py
Normal file
30
savannadashboard/job_executions/panel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class JobExecutionsPanel(horizon.Panel):
|
||||||
|
name = _("Job Executions")
|
||||||
|
slug = 'job_executions'
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.SavannaDashboard.register(JobExecutionsPanel)
|
62
savannadashboard/job_executions/tables.py
Normal file
62
savannadashboard/job_executions/tables.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
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):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
savanna.job_executions.delete(obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class JobExecutionsTable(tables.DataTable):
|
||||||
|
class StatusColumn(tables.Column):
|
||||||
|
def get_data(self, datum):
|
||||||
|
return datum.info['status']
|
||||||
|
|
||||||
|
name = tables.Column("id",
|
||||||
|
verbose_name=_("ID"),
|
||||||
|
display_choices=(("id", "ID"), ("name", "Name")),
|
||||||
|
link=("horizon:savanna:job_executions:details"))
|
||||||
|
|
||||||
|
status = StatusColumn("info",
|
||||||
|
verbose_name=_("Status"))
|
||||||
|
|
||||||
|
def get_object_display(self, datum):
|
||||||
|
return datum.id
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
name = "job_executions"
|
||||||
|
verbose_name = _("Job Executions")
|
||||||
|
table_actions = [DeleteJobExecution]
|
||||||
|
row_actions = [DeleteJobExecution]
|
44
savannadashboard/job_executions/tabs.py
Normal file
44
savannadashboard/job_executions/tabs.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
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']
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
job_execution = savanna.job_executions.get(job_execution_id)
|
||||||
|
return {"job_execution": job_execution}
|
||||||
|
|
||||||
|
|
||||||
|
class JobExecutionDetailsTabs(tabs.TabGroup):
|
||||||
|
slug = "job_execution_details"
|
||||||
|
tabs = (GeneralTab,)
|
||||||
|
sticky = True
|
31
savannadashboard/job_executions/urls.py
Normal file
31
savannadashboard/job_executions/urls.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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.conf.urls.defaults import patterns
|
||||||
|
from django.conf.urls.defaults import url
|
||||||
|
|
||||||
|
import savannadashboard.job_executions.views as views
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^$', views.JobExecutionsView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
url(r'^$', views.JobExecutionsView.as_view(),
|
||||||
|
name='job-executions'),
|
||||||
|
url(r'^(?P<job_execution_id>[^/]+)$',
|
||||||
|
views.JobExecutionDetailsView.as_view(),
|
||||||
|
name='details'))
|
51
savannadashboard/job_executions/views.py
Normal file
51
savannadashboard/job_executions/views.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
from savannadashboard.job_executions.tables import JobExecutionsTable
|
||||||
|
import savannadashboard.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):
|
||||||
|
savanna = savannaclient.Client(self.request)
|
||||||
|
jobs = savanna.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
|
@ -50,8 +50,6 @@ class JobOriginsTable(tables.DataTable):
|
|||||||
name = tables.Column("name",
|
name = tables.Column("name",
|
||||||
verbose_name=_("Name"),
|
verbose_name=_("Name"),
|
||||||
link=("horizon:savanna:job_origins:details"))
|
link=("horizon:savanna:job_origins:details"))
|
||||||
type = tables.Column("type",
|
|
||||||
verbose_name=_("Type"))
|
|
||||||
description = tables.Column("description",
|
description = tables.Column("description",
|
||||||
verbose_name=_("Description"))
|
verbose_name=_("Description"))
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.forms.util import flatatt
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
@ -24,40 +26,85 @@ from horizon import workflows
|
|||||||
|
|
||||||
from savannadashboard.api import client as savannaclient
|
from savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AddExtraSelectWidget(forms.Select):
|
||||||
|
def render(self, name, value, attrs=None, choices=()):
|
||||||
|
if value is None:
|
||||||
|
value = ''
|
||||||
|
final_attrs = self.build_attrs(attrs, name=name)
|
||||||
|
output = [u'<select%s>' % flatatt(final_attrs)]
|
||||||
|
options = self.render_options(choices, [value])
|
||||||
|
if options:
|
||||||
|
output.append(options)
|
||||||
|
output.append('</select>')
|
||||||
|
output.append("<input type='button' " +
|
||||||
|
"class='job_binary_add_button' value='Add' " +
|
||||||
|
"onclick='addExtraBinary(this);'></input>")
|
||||||
|
return mark_safe("".join(output))
|
||||||
|
|
||||||
|
|
||||||
class GeneralConfigAction(workflows.Action):
|
class GeneralConfigAction(workflows.Action):
|
||||||
|
NUM_LOCATION_FIELDS = 10
|
||||||
|
FIELDS_BEFORE_MAIN = 2
|
||||||
|
local_binary_choices = []
|
||||||
|
extra_binary_count = forms.CharField(widget=forms.HiddenInput())
|
||||||
|
|
||||||
job_origin_name = forms.CharField(label=_("Name"),
|
job_origin_name = forms.CharField(label=_("Name"),
|
||||||
required=True)
|
required=True)
|
||||||
|
|
||||||
job_origin_credential_user = forms.CharField(label=_("Origin username"),
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
job_origin_credential_pass = forms.CharField(
|
|
||||||
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
|
||||||
label=_("Origin password"),
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
job_storage_type = forms.ChoiceField(
|
|
||||||
label=_("Job Storage Type"),
|
|
||||||
required=True,
|
|
||||||
choices=[("internal", "Savanna DB"),
|
|
||||||
("swift", "Swift"),
|
|
||||||
("hdfs", "HDFS")],
|
|
||||||
widget=forms.Select(
|
|
||||||
attrs={"class": "job_storage_type_choice"}))
|
|
||||||
|
|
||||||
job_origin_location = forms.CharField(label=_("Job Storage Location"),
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
job_origin_description = forms.CharField(label=_("Description"),
|
job_origin_description = forms.CharField(label=_("Description"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.Textarea)
|
widget=forms.Textarea)
|
||||||
|
|
||||||
|
def populate_job_origin_local_db_choices(self, request):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
job_binaries = savanna.job_binaries.list()
|
||||||
|
|
||||||
|
choices = [(job_binary.id, job_binary.name)
|
||||||
|
for job_binary in job_binaries]
|
||||||
|
choices.insert(0, ('', 'NONE'))
|
||||||
|
|
||||||
|
return choices
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
extra_fields = kwargs.pop('extra', 0)
|
||||||
|
|
||||||
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
super(GeneralConfigAction, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
self.fields['extra_binary_count'].initial = extra_fields
|
||||||
|
self.local_binary_choices =\
|
||||||
|
self.populate_job_origin_local_db_choices(request)
|
||||||
|
|
||||||
|
for i in range(self.NUM_LOCATION_FIELDS, 0, -1):
|
||||||
|
self.fields.insert(
|
||||||
|
self.FIELDS_BEFORE_MAIN, 'job_origin_main_%s' % i,
|
||||||
|
forms.ChoiceField(
|
||||||
|
label=_("Main Binary"),
|
||||||
|
required=False,
|
||||||
|
choices=self.local_binary_choices,
|
||||||
|
initial=(None, "None"),
|
||||||
|
widget=AddExtraSelectWidget(
|
||||||
|
attrs={"class": "job_origin_main"})))
|
||||||
|
|
||||||
|
for i in range(self.NUM_LOCATION_FIELDS, 0, -1):
|
||||||
|
self.fields.insert(
|
||||||
|
self.FIELDS_BEFORE_MAIN + self.NUM_LOCATION_FIELDS,
|
||||||
|
'job_origin_lib_%s' % i,
|
||||||
|
forms.ChoiceField(
|
||||||
|
label=_("Library"),
|
||||||
|
required=False,
|
||||||
|
choices=self.local_binary_choices,
|
||||||
|
initial=(None, "None"),
|
||||||
|
widget=AddExtraSelectWidget(
|
||||||
|
attrs={"class": "job_origin_lib"})))
|
||||||
|
|
||||||
|
self.fields["extra_locations"] = forms.CharField(
|
||||||
|
widget=forms.HiddenInput(),
|
||||||
|
initial=self.NUM_LOCATION_FIELDS)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
name = _("Create Job Origin")
|
name = _("Create Job Origin")
|
||||||
help_text_template = \
|
help_text_template = \
|
||||||
@ -66,7 +113,6 @@ class GeneralConfigAction(workflows.Action):
|
|||||||
|
|
||||||
class GeneralConfig(workflows.Step):
|
class GeneralConfig(workflows.Step):
|
||||||
action_class = GeneralConfigAction
|
action_class = GeneralConfigAction
|
||||||
contributes = ("hidden_configure_field", )
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
def contribute(self, data, context):
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
@ -86,11 +132,23 @@ class CreateJobOrigin(workflows.Workflow):
|
|||||||
|
|
||||||
def handle(self, request, context):
|
def handle(self, request, context):
|
||||||
savanna = savannaclient.Client(request)
|
savanna = savannaclient.Client(request)
|
||||||
|
main_locations = []
|
||||||
|
lib_locations = []
|
||||||
|
|
||||||
|
extra_count = 2
|
||||||
|
for i in range(1, extra_count + 1):
|
||||||
|
if(context["general_job_origin_main_%s" % i] != ""):
|
||||||
|
main_locations.append(
|
||||||
|
context["general_job_origin_main_%s" % i])
|
||||||
|
|
||||||
|
for i in range(1, extra_count + 1):
|
||||||
|
if(context["general_job_origin_lib_%s" % i] != ""):
|
||||||
|
lib_locations.append(
|
||||||
|
context["general_job_origin_lib_%s" % i])
|
||||||
|
|
||||||
savanna.job_origins.create(
|
savanna.job_origins.create(
|
||||||
context["general_job_origin_name"],
|
context["general_job_origin_name"],
|
||||||
context["general_job_storage_type"],
|
main_locations,
|
||||||
context["general_job_origin_credential_user"],
|
lib_locations,
|
||||||
context["general_job_origin_credential_pass"],
|
|
||||||
context["general_job_origin_location"],
|
|
||||||
context["general_job_origin_description"])
|
context["general_job_origin_description"])
|
||||||
return True
|
return True
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.core import urlresolvers
|
||||||
|
from django.utils import http
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
@ -46,6 +48,23 @@ class DeleteJob(tables.BatchAction):
|
|||||||
savanna.jobs.delete(obj_id)
|
savanna.jobs.delete(obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class LaunchJob(tables.LinkAction):
|
||||||
|
name = "launch-job"
|
||||||
|
verbose_name = _("Launch Job")
|
||||||
|
action_present = _("Launch")
|
||||||
|
action_past = _("Launched")
|
||||||
|
data_type_singular = _("Job")
|
||||||
|
data_type_plural = _("Jobs")
|
||||||
|
url = "horizon:savanna: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 JobsTable(tables.DataTable):
|
class JobsTable(tables.DataTable):
|
||||||
name = tables.Column("name",
|
name = tables.Column("name",
|
||||||
verbose_name=_("Name"),
|
verbose_name=_("Name"),
|
||||||
@ -60,4 +79,4 @@ class JobsTable(tables.DataTable):
|
|||||||
verbose_name = _("Jobs")
|
verbose_name = _("Jobs")
|
||||||
table_actions = (CreateJob,
|
table_actions = (CreateJob,
|
||||||
DeleteJob)
|
DeleteJob)
|
||||||
row_actions = (DeleteJob,)
|
row_actions = (LaunchJob, DeleteJob,)
|
||||||
|
@ -29,6 +29,9 @@ urlpatterns = patterns('',
|
|||||||
url(r'^create-job$',
|
url(r'^create-job$',
|
||||||
views.CreateJobView.as_view(),
|
views.CreateJobView.as_view(),
|
||||||
name='create-job'),
|
name='create-job'),
|
||||||
|
url(r'^launch-job$',
|
||||||
|
views.LaunchJobView.as_view(),
|
||||||
|
name='launch-job'),
|
||||||
url(r'^(?P<job_id>[^/]+)$',
|
url(r'^(?P<job_id>[^/]+)$',
|
||||||
views.JobDetailsView.as_view(),
|
views.JobDetailsView.as_view(),
|
||||||
name='details'))
|
name='details'))
|
||||||
|
@ -26,6 +26,7 @@ from savannadashboard.api import client as savannaclient
|
|||||||
from savannadashboard.jobs.tables import JobsTable
|
from savannadashboard.jobs.tables import JobsTable
|
||||||
import savannadashboard.jobs.tabs as _tabs
|
import savannadashboard.jobs.tabs as _tabs
|
||||||
import savannadashboard.jobs.workflows.create as create_flow
|
import savannadashboard.jobs.workflows.create as create_flow
|
||||||
|
import savannadashboard.jobs.workflows.launch as launch_flow
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,3 +60,16 @@ class JobDetailsView(tabs.TabView):
|
|||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LaunchJobView(workflows.WorkflowView):
|
||||||
|
workflow_class = launch_flow.LaunchJob
|
||||||
|
success_url = \
|
||||||
|
"horizon:savanna:jobs"
|
||||||
|
classes = ("ajax-modal")
|
||||||
|
template_name = "jobs/launch.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(LaunchJobView, self)\
|
||||||
|
.get_context_data(**kwargs)
|
||||||
|
return context
|
||||||
|
154
savannadashboard/jobs/workflows/launch.py
Normal file
154
savannadashboard/jobs/workflows/launch.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# 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 savannadashboard.api import client as savannaclient
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralConfigAction(workflows.Action):
|
||||||
|
cluster = forms.ChoiceField(
|
||||||
|
label=_("Cluster"),
|
||||||
|
required=True,
|
||||||
|
initial=(None, "None"),
|
||||||
|
widget=forms.Select(attrs={"class": "cluster_choice"}))
|
||||||
|
|
||||||
|
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(GeneralConfigAction, 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_cluster_choices(self, request, context):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
clusters = savanna.clusters.list()
|
||||||
|
|
||||||
|
choices = [(cluster.id, cluster.name)
|
||||||
|
for cluster in clusters]
|
||||||
|
|
||||||
|
return choices
|
||||||
|
|
||||||
|
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):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
data_sources = savanna.data_sources.list()
|
||||||
|
|
||||||
|
choices = [(data_source.id, data_source.name)
|
||||||
|
for data_source in data_sources]
|
||||||
|
|
||||||
|
return choices
|
||||||
|
|
||||||
|
def populate_job_choices(self, request):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
jobs = savanna.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 JobConfigAction(workflows.Action):
|
||||||
|
config = forms.CharField(
|
||||||
|
label=_("Job Config"),
|
||||||
|
widget=forms.Textarea())
|
||||||
|
|
||||||
|
def __init__(self, request, *args, **kwargs):
|
||||||
|
super(JobConfigAction, self).__init__(request, *args, **kwargs)
|
||||||
|
# TODO(croberts) pre-populate config with job-type
|
||||||
|
# appropriate config settings
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
name = _("Configure")
|
||||||
|
help_text_template = \
|
||||||
|
("jobs/_launch_job_configure_help.html")
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralConfig(workflows.Step):
|
||||||
|
action_class = GeneralConfigAction
|
||||||
|
|
||||||
|
def contribute(self, data, context):
|
||||||
|
for k, v in data.items():
|
||||||
|
context["general_" + k] = v
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class JobConfig(workflows.Step):
|
||||||
|
action_class = JobConfigAction
|
||||||
|
|
||||||
|
def contribute(self, data, context):
|
||||||
|
for k, v in data.items():
|
||||||
|
context["job_" + 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:savanna:jobs:index"
|
||||||
|
default_steps = (GeneralConfig, JobConfig)
|
||||||
|
|
||||||
|
def handle(self, request, context):
|
||||||
|
savanna = savannaclient.Client(request)
|
||||||
|
savanna.jobs.launch(
|
||||||
|
context["general_job"],
|
||||||
|
context["general_cluster"],
|
||||||
|
context["general_job_input"],
|
||||||
|
context["general_job_output"],
|
||||||
|
context["job_config"])
|
||||||
|
return True
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<div class="cluster_templates">
|
<div class="data_sources">
|
||||||
{{ data_sources_table.render }}
|
{{ data_sources_table.render }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
21
savannadashboard/templates/job_binaries/_create.html
Normal file
21
savannadashboard/templates/job_binaries/_create.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_id %}create-job-binary{% endblock %}
|
||||||
|
{% block form_action %}{% url horizon:savanna: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>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" id="upload_file_btn" type="submit" value="{% trans "Create" %}"/>
|
||||||
|
<a href="{% url horizon:savanna:job_binaries:index %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
18
savannadashboard/templates/job_binaries/_details.html
Normal file
18
savannadashboard/templates/job_binaries/_details.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% load i18n sizeformat %}
|
||||||
|
<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 "Tenant id" %}</dt>
|
||||||
|
<dd>{{ job_binary.tenant_id }}</dd>
|
||||||
|
<dt>{% trans "Create time" %}</dt>
|
||||||
|
<dd>{{ job_binary.created_at }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
11
savannadashboard/templates/job_binaries/create.html
Normal file
11
savannadashboard/templates/job_binaries/create.html
Normal file
@ -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=_("Savanna - Create Job Binary") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'job_binaries/_create.html' %}
|
||||||
|
{% endblock %}
|
15
savannadashboard/templates/job_binaries/details.html
Normal file
15
savannadashboard/templates/job_binaries/details.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n sizeformat %}
|
||||||
|
{% block title %}{% trans "Job Binary Details" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Savanna - Job Binary Details") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
84
savannadashboard/templates/job_binaries/job_binaries.html
Normal file
84
savannadashboard/templates/job_binaries/job_binaries.html
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Savanna" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Savanna - Job Binaries") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<style type="text/css">
|
||||||
|
#id_job_binary_url {
|
||||||
|
width: 200px !important; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="job_binaries">
|
||||||
|
{{ job_binaries_table.render }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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_savanna_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_savanna_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");
|
||||||
|
switch($(this).val()) {
|
||||||
|
case "savanna-db":
|
||||||
|
label.html("savanna-db://");
|
||||||
|
username.hide();
|
||||||
|
password.hide();
|
||||||
|
bin_file.show();
|
||||||
|
bin_choice.show();
|
||||||
|
bin_url.hide();
|
||||||
|
break;
|
||||||
|
case "swift-external":
|
||||||
|
username.hide();
|
||||||
|
password.hide();
|
||||||
|
bin_file.hide();
|
||||||
|
bin_choice.hide();
|
||||||
|
bin_url.show()
|
||||||
|
label.html("swift-external://");
|
||||||
|
break;
|
||||||
|
case "swift-internal":
|
||||||
|
username.show();
|
||||||
|
password.show();
|
||||||
|
bin_file.hide();
|
||||||
|
bin_choice.hide();
|
||||||
|
bin_url.show();
|
||||||
|
label.html("swift-internal://");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#id_job_binary_type").change();
|
||||||
|
|
||||||
|
$("[name=job_binary_savanna_internal]").change(function() {
|
||||||
|
var bin_file = $("[name=job_binary_file]").closest(".control-group");
|
||||||
|
var bin_choice = $("[name=job_binary_savanna_internal]").closest(".control-group");
|
||||||
|
var bin_url = $("[name=job_binary_url]").closest(".control-group");
|
||||||
|
switch($(this).val()) {
|
||||||
|
case "":
|
||||||
|
bin_file.show();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bin_file.hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#job_binary_savanna_internal").change();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
28
savannadashboard/templates/job_executions/_details.html
Normal file
28
savannadashboard/templates/job_executions/_details.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% load i18n sizeformat %}
|
||||||
|
<h3>{% trans "Job Execution Overview" %}</h3>
|
||||||
|
<div class="status row-fluid detail">
|
||||||
|
<dl>
|
||||||
|
<dt>{% trans "Status" %}</dt>
|
||||||
|
<dd>{{ job_execution.info.status }}</dd>
|
||||||
|
<dt>{% trans "Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.id }}</dd>
|
||||||
|
<dt>{% trans "Job Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.job_id }}</dd>
|
||||||
|
<dt>{% trans "Input Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.input_id }}</dd>
|
||||||
|
<dt>{% trans "Output Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.output_id }}</dd>
|
||||||
|
<dt>{% trans "Cluster Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.cluster_id }}</dd>
|
||||||
|
<dt>{% trans "Last Updated" %}</dt>
|
||||||
|
<dd>{{ job_execution.updated_at }}</dd>
|
||||||
|
<dt>{% trans "Return Code" %}</dt>
|
||||||
|
<dd>{{ job_execution.return_code }}</dd>
|
||||||
|
<dt>{% trans "Oozie Job Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.oozie_job_id }}</dd>
|
||||||
|
<dt>{% trans "Created" %}</dt>
|
||||||
|
<dd>{{ job_execution.created_at }}</dd>
|
||||||
|
<dt>{% trans "Tenant Id" %}</dt>
|
||||||
|
<dd>{{ job_execution.tenant_id }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
15
savannadashboard/templates/job_executions/details.html
Normal file
15
savannadashboard/templates/job_executions/details.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n sizeformat %}
|
||||||
|
{% block title %}{% trans "Job Execution Details" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Savanna - Job Execution Details") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
{{ tab_group.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Savanna" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Savanna - Job Executions") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<div class="job_executions">
|
||||||
|
{{ job_executions_table.render }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -6,14 +6,6 @@
|
|||||||
<dd>{{ job_origin.name }}</dd>
|
<dd>{{ job_origin.name }}</dd>
|
||||||
<dt>{% trans "ID" %}</dt>
|
<dt>{% trans "ID" %}</dt>
|
||||||
<dd>{{ job_origin.id }}</dd>
|
<dd>{{ job_origin.id }}</dd>
|
||||||
<dt>{% trans "URL" %}</dt>
|
|
||||||
<dd>{{ job_origin.url }}</dd>
|
|
||||||
<dt>{% trans "Storage type" %}</dt>
|
|
||||||
<dd>{{ job_origin.storage_type }}</dd>
|
|
||||||
<dt>{% trans "Username" %}</dt>
|
|
||||||
<dd>{{ job_origin.credentials.user|default:"None" }}</dd>
|
|
||||||
<dt>{% trans "Password" %}</dt>
|
|
||||||
<dd>{{ job_origin.credentials.password|default:"None" }}</dd>
|
|
||||||
<dt>{% trans "Description" %}</dt>
|
<dt>{% trans "Description" %}</dt>
|
||||||
<dd>{{ job_origin.description|default:"None" }}</dd>
|
<dd>{{ job_origin.description|default:"None" }}</dd>
|
||||||
<dt>{% trans "Tenant id" %}</dt>
|
<dt>{% trans "Tenant id" %}</dt>
|
||||||
|
@ -7,9 +7,39 @@
|
|||||||
{% endblock page_header %}
|
{% endblock page_header %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
<style type="text/css">
|
||||||
<div class="cluster_templates">
|
.job_origin_main, .job_origin_lib {
|
||||||
|
width: 200px !important; }
|
||||||
|
.job_binary_add_button, .job_binary_remove_button {
|
||||||
|
width: 80px !important;
|
||||||
|
margin-left: 5px; }
|
||||||
|
</style>
|
||||||
|
<div class="job_origins">
|
||||||
{{ job_origins_table.render }}
|
{{ job_origins_table.render }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
addHorizonLoadEvent(function () {
|
||||||
|
horizon.modals.addModalInitFunction(function (modal) {
|
||||||
|
hide_extra_fields();
|
||||||
|
|
||||||
|
function hide_extra_fields() {
|
||||||
|
for(i=2; i <= $("[name=extra_locations]").val(); i++) {
|
||||||
|
$("[name=job_origin_main_" + i + "]").closest(".control-group").hide();
|
||||||
|
$("[name=job_origin_lib_" + i + "]").closest(".control-group").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
addExtraBinary = function (where_from) {
|
||||||
|
var loc_type = where_from.previousSibling.name.contains("main") ? "main" : "lib";
|
||||||
|
for(i=2; i <= $("[name=extra_locations]").val(); i++) {
|
||||||
|
if (!$("[name=job_origin_" + loc_type + "_" + i + "]").closest(".control-group").is(":visible")) {
|
||||||
|
$("[name=job_origin_" + loc_type + "_" + i + "]").closest(".control-group").show();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<div class="cluster_templates">
|
<div class="jobs">
|
||||||
{{ jobs_table.render }}
|
{{ jobs_table.render }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
11
savannadashboard/templates/jobs/launch.html
Normal file
11
savannadashboard/templates/jobs/launch.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Launch Job" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Savanna - Launch Job") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'horizon/common/_workflow.html' %}
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user