Merge "[Sahara] Unified job interface map UI"
This commit is contained in:
commit
d6ce0cf9f0
@ -380,13 +380,14 @@ def job_binary_internal_delete(request, jbi_id):
|
||||
client(request).job_binary_internals.delete(job_binary_id=jbi_id)
|
||||
|
||||
|
||||
def job_create(request, name, j_type, mains, libs, description):
|
||||
def job_create(request, name, j_type, mains, libs, description, interface):
|
||||
return client(request).jobs.create(
|
||||
name=name,
|
||||
type=j_type,
|
||||
mains=mains,
|
||||
libs=libs,
|
||||
description=description)
|
||||
description=description,
|
||||
interface=interface)
|
||||
|
||||
|
||||
def job_list(request, search_opts=None):
|
||||
@ -406,13 +407,15 @@ def job_get_configs(request, job_type):
|
||||
|
||||
|
||||
def job_execution_create(request, job_id, cluster_id,
|
||||
input_id, output_id, configs):
|
||||
input_id, output_id, configs,
|
||||
interface):
|
||||
return client(request).job_executions.create(
|
||||
job_id=job_id,
|
||||
cluster_id=cluster_id,
|
||||
input_id=input_id,
|
||||
output_id=output_id,
|
||||
configs=configs)
|
||||
configs=configs,
|
||||
interface=interface)
|
||||
|
||||
|
||||
def _resolve_job_execution_names(job_execution, cluster=None,
|
||||
|
@ -0,0 +1,43 @@
|
||||
{% load i18n %}
|
||||
<input type="hidden" value="[]" name="argument_ids" id="argument_ids">
|
||||
<label for="value_type">{% trans "Select a Value Type for your next argument:" %}</label>
|
||||
<span class="row">
|
||||
<span class="input-group col-sm-4">
|
||||
<select id="value_type" name="value_type" class="form-control">
|
||||
<option>{% trans "Select" %}</option>
|
||||
<option value="string">{% trans "String" %}</option>
|
||||
<option value="number">{% trans "Number" %}</option>
|
||||
<option value="data_source">{% trans "Data Source" %}</option>
|
||||
</select>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" id="add_argument_button" class="btn btn-default disabled" onclick="horizon.job_interface_arguments.add_interface_argument();">
|
||||
<span class="fa fa-plus"></span>
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<div id="job_interface_arguments">
|
||||
<div id="arguments_table">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function () {
|
||||
horizon.job_interface_arguments.init_arguments();
|
||||
{% for argument in form.arguments %}
|
||||
horizon.job_interface_arguments.add_argument_node(
|
||||
horizon.job_interface_arguments.get_next_argument_id(),
|
||||
"{{ argument.name }}",
|
||||
"{{ argument.description }}",
|
||||
"{{ argument.mapping_type }}",
|
||||
"{{ argument.location }}",
|
||||
"{{ argument.value_type }}",
|
||||
"{{ argument.required }}",
|
||||
"{{ argument.default_value }}");
|
||||
{% endfor %}
|
||||
{% for field_id in form.errors_fields %}
|
||||
horizon.job_interface_arguments.mark_argument_element_as_wrong("{{ field_id }}");
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
</script>
|
@ -34,9 +34,6 @@
|
||||
$navbar.hide();
|
||||
}
|
||||
|
||||
$(".hidden_nodegroups_field").val("");
|
||||
$(".hidden_configure_field").val("");
|
||||
|
||||
lower_limit = 0;
|
||||
$(".count-field").change();
|
||||
if ($(modal).find(".hidden_create_field").length > 0) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% load i18n %}
|
||||
<script type="text/javascript">
|
||||
var remove_btn_label = '{% trans "Remove" %}';
|
||||
var template = '<tr id_attr="$id">' +
|
||||
var lib_template = '<tr id_attr="$id">' +
|
||||
'<td>' +
|
||||
'<div class="input form-group" style="padding-right:15px;"><input disabled value="$lib_name" class="form-control" /></div>' +
|
||||
'</td>' +
|
||||
@ -17,7 +17,7 @@
|
||||
'</td>' +
|
||||
'</tr>';
|
||||
|
||||
function get_next_id() {
|
||||
function get_next_lib_id() {
|
||||
var max = -1;
|
||||
$("#libs tbody tr").each(function () {
|
||||
max = Math.max(max, parseInt($(this).attr("id_attr")));
|
||||
@ -33,8 +33,8 @@
|
||||
$("#lib_ids").val(JSON.stringify(ids));
|
||||
}
|
||||
|
||||
function add_node(lib_name, id) {
|
||||
var tmp = template.
|
||||
function add_lib_node(lib_name, id) {
|
||||
var tmp = lib_template.
|
||||
replace(/\$id/g, id).
|
||||
replace(/\$lib_name/g, lib_name);
|
||||
$("#libs tbody").append(tmp);
|
||||
@ -50,12 +50,12 @@
|
||||
if (lib_val == "") {
|
||||
return;
|
||||
}
|
||||
add_node(chosen.html(), chosen.val());
|
||||
add_lib_node(chosen.html(), chosen.val());
|
||||
}
|
||||
function delete_lib(el) {
|
||||
var tr = $(el).parents("tr")[0];
|
||||
tr.parentNode.removeChild(tr);
|
||||
var id = get_next_id();
|
||||
var id = get_next_lib_id();
|
||||
if (id == 0) {
|
||||
$("#libs").hide();
|
||||
}
|
||||
|
@ -54,7 +54,8 @@ class DataProcessingJobTests(test.TestCase):
|
||||
api.sahara.job_binary_list(IsA(http.HttpRequest)).AndReturn([])
|
||||
api.sahara.job_binary_list(IsA(http.HttpRequest)).AndReturn([])
|
||||
api.sahara.job_create(IsA(http.HttpRequest),
|
||||
'test', 'Pig', [], [], 'test create')
|
||||
'test', 'Pig', [], [], 'test create',
|
||||
interface=[])
|
||||
api.sahara.job_types_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.job_types.list())
|
||||
self.mox.ReplayAll()
|
||||
@ -62,7 +63,66 @@ class DataProcessingJobTests(test.TestCase):
|
||||
'job_type': 'pig',
|
||||
'lib_binaries': [],
|
||||
'lib_ids': '[]',
|
||||
'job_description': 'test create'}
|
||||
'job_description': 'test create',
|
||||
'hidden_arguments_field': [],
|
||||
'argument_ids': '[]'}
|
||||
url = reverse('horizon:project:data_processing.jobs:create-job')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({api.sahara: ('job_binary_list',
|
||||
'job_create',
|
||||
'job_types_list')})
|
||||
def test_create_with_interface(self):
|
||||
api.sahara.job_binary_list(IsA(http.HttpRequest)).AndReturn([])
|
||||
api.sahara.job_binary_list(IsA(http.HttpRequest)).AndReturn([])
|
||||
api.sahara.job_create(IsA(http.HttpRequest),
|
||||
'test_interface', 'Pig', [], [], 'test create',
|
||||
interface=[
|
||||
{
|
||||
"name": "argument",
|
||||
"description": None,
|
||||
"mapping_type": "args",
|
||||
"location": "0",
|
||||
"value_type": "number",
|
||||
"required": True,
|
||||
"default": None
|
||||
},
|
||||
{
|
||||
"name": "config",
|
||||
"description": "Really great config",
|
||||
"mapping_type": "configs",
|
||||
"location": "edp.important.config",
|
||||
"value_type": "string",
|
||||
"required": False,
|
||||
"default": "A value"
|
||||
}])
|
||||
api.sahara.job_types_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.job_types.list())
|
||||
self.mox.ReplayAll()
|
||||
form_data = {'job_name': 'test_interface',
|
||||
'job_type': 'pig',
|
||||
'lib_binaries': [],
|
||||
'lib_ids': '[]',
|
||||
'job_description': 'test create',
|
||||
'hidden_arguments_field': [],
|
||||
'argument_ids': '["0", "1"]',
|
||||
'argument_id_0': '0',
|
||||
'argument_name_0': 'argument',
|
||||
'argument_description_0': '',
|
||||
'argument_mapping_type_0': 'args',
|
||||
'argument_location_0': '0',
|
||||
'argument_value_type_0': 'number',
|
||||
'argument_required_0': True,
|
||||
'argument_default_value_0': '',
|
||||
'argument_id_1': '1',
|
||||
'argument_name_1': 'config',
|
||||
'argument_description_1': 'Really great config',
|
||||
'argument_mapping_type_1': 'configs',
|
||||
'argument_location_1': 'edp.important.config',
|
||||
'argument_value_type_1': 'string',
|
||||
'argument_default_value_1': 'A value'}
|
||||
url = reverse('horizon:project:data_processing.jobs:create-job')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
@ -106,11 +166,14 @@ class DataProcessingJobTests(test.TestCase):
|
||||
.MultipleTimes().AndReturn(self.data_sources.list())
|
||||
api.sahara.job_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.jobs.list())
|
||||
api.sahara.job_get(IsA(http.HttpRequest), IsA(unicode)) \
|
||||
.AndReturn(job)
|
||||
api.sahara.job_execution_create(IsA(http.HttpRequest),
|
||||
IsA(unicode),
|
||||
IsA(unicode),
|
||||
IsA(unicode),
|
||||
IsA(unicode),
|
||||
IsA(dict),
|
||||
IsA(dict)).AndReturn(job_execution)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -121,6 +184,7 @@ class DataProcessingJobTests(test.TestCase):
|
||||
'job_input': input_ds.id,
|
||||
'job_output': output_ds.id,
|
||||
'config': {},
|
||||
'argument_ids': '{}',
|
||||
'adapt_oozie': 'on',
|
||||
'hbase_common_lib': 'on',
|
||||
'java_opts': '',
|
||||
|
@ -23,6 +23,8 @@ from horizon import workflows
|
||||
|
||||
from openstack_dashboard.contrib.sahara.content.data_processing \
|
||||
.utils import helpers
|
||||
import openstack_dashboard.contrib.sahara.content.data_processing \
|
||||
.utils.workflow_helpers as whelpers
|
||||
from openstack_dashboard.contrib.sahara.api import sahara as saharaclient
|
||||
|
||||
|
||||
@ -140,6 +142,62 @@ class GeneralConfigAction(workflows.Action):
|
||||
"project/data_processing.jobs/_create_job_help.html")
|
||||
|
||||
|
||||
class ConfigureInterfaceArgumentsAction(workflows.Action):
|
||||
hidden_arguments_field = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput(attrs={"class": "hidden_arguments_field"}))
|
||||
argument_ids = forms.CharField(
|
||||
required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(ConfigureInterfaceArgumentsAction, self).__init__(
|
||||
request, *args, **kwargs)
|
||||
request_source = None
|
||||
if 'argument_ids' in request.POST:
|
||||
request_source = request.POST
|
||||
elif 'argument_ids' in request.REQUEST:
|
||||
request_source = request.REQUEST
|
||||
if request_source:
|
||||
self.arguments = []
|
||||
for id in json.loads(request_source['argument_ids']):
|
||||
fields = {
|
||||
"name": "argument_name_" + str(id),
|
||||
"description": "argument_description_" + str(id),
|
||||
"mapping_type": "argument_mapping_type_" + str(id),
|
||||
"location": "argument_location_" + str(id),
|
||||
"value_type": "argument_value_type_" + str(id),
|
||||
"default_value": "argument_default_value_" + str(id)}
|
||||
argument = {k: request_source[v]
|
||||
for k, v in fields.items()}
|
||||
required_field = "argument_required_" + str(id)
|
||||
fields.update({"required": required_field})
|
||||
argument.update(
|
||||
{"required": required_field in request_source})
|
||||
self.arguments.append(argument)
|
||||
|
||||
whelpers.build_interface_argument_fields(self, **fields)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(ConfigureInterfaceArgumentsAction, self).clean()
|
||||
return cleaned_data
|
||||
|
||||
class Meta(object):
|
||||
name = _("Interface Arguments")
|
||||
|
||||
|
||||
class ConfigureArguments(workflows.Step):
|
||||
action_class = ConfigureInterfaceArgumentsAction
|
||||
contributes = ("hidden_arguments_field", )
|
||||
template_name = ("project/data_processing.jobs/"
|
||||
"job_interface_arguments_template.html")
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context[k] = v
|
||||
return context
|
||||
|
||||
|
||||
class GeneralConfig(workflows.Step):
|
||||
action_class = GeneralConfigAction
|
||||
contributes = ("job_name", "job_type", "job_description", "main_binary")
|
||||
@ -171,7 +229,7 @@ class CreateJob(workflows.Workflow):
|
||||
success_message = _("Job created")
|
||||
failure_message = _("Could not create job template")
|
||||
success_url = "horizon:project:data_processing.jobs:index"
|
||||
default_steps = (GeneralConfig, ConfigureLibs)
|
||||
default_steps = (GeneralConfig, ConfigureLibs, ConfigureArguments)
|
||||
|
||||
def handle(self, request, context):
|
||||
main_locations = []
|
||||
@ -184,6 +242,22 @@ class CreateJob(workflows.Workflow):
|
||||
if context.get("main_binary", None):
|
||||
main_locations.append(context["main_binary"])
|
||||
|
||||
argument_ids = json.loads(context['argument_ids'])
|
||||
interface = [
|
||||
{
|
||||
"name": context['argument_name_' + str(arg_id)],
|
||||
"description": (context['argument_description_' + str(arg_id)]
|
||||
or None),
|
||||
"mapping_type": context['argument_mapping_type_'
|
||||
+ str(arg_id)],
|
||||
"location": context['argument_location_' + str(arg_id)],
|
||||
"value_type": context['argument_value_type_' + str(arg_id)],
|
||||
"required": context['argument_required_' + str(arg_id)],
|
||||
"default": (context['argument_default_value_' + str(arg_id)]
|
||||
or None)
|
||||
} for arg_id in argument_ids
|
||||
]
|
||||
|
||||
try:
|
||||
job = saharaclient.job_create(
|
||||
request,
|
||||
@ -191,7 +265,8 @@ class CreateJob(workflows.Workflow):
|
||||
context["job_type"],
|
||||
main_locations,
|
||||
lib_locations,
|
||||
context["job_description"])
|
||||
context["job_description"],
|
||||
interface=interface)
|
||||
|
||||
hlps = helpers.Helpers(request)
|
||||
if hlps.is_from_guide():
|
||||
|
@ -127,6 +127,33 @@ class JobExecutionExistingGeneralConfigAction(JobExecutionGeneralConfigAction):
|
||||
"project/data_processing.jobs/_launch_job_help.html")
|
||||
|
||||
|
||||
def _merge_interface_with_configs(interface, job_configs):
|
||||
interface_by_mapping = {(arg['mapping_type'], arg['location']): arg
|
||||
for arg in interface}
|
||||
mapped_types = ("configs", "params")
|
||||
mapped_configs = {
|
||||
(mapping_type, key): value for mapping_type in mapped_types
|
||||
for key, value in job_configs.get(mapping_type, {}).items()
|
||||
}
|
||||
for index, arg in enumerate(job_configs.get('args', [])):
|
||||
mapped_configs['args', str(index)] = arg
|
||||
free_arguments, interface_arguments = {}, {}
|
||||
for mapping, value in mapped_configs.items():
|
||||
if mapping in interface_by_mapping:
|
||||
arg = interface_by_mapping[mapping]
|
||||
interface_arguments[arg['id']] = value
|
||||
else:
|
||||
free_arguments[mapping] = value
|
||||
configs = {"configs": {}, "params": {}, "args": {}}
|
||||
for mapping, value in free_arguments.items():
|
||||
mapping_type, location = mapping
|
||||
configs[mapping_type][location] = value
|
||||
configs["args"] = [
|
||||
value for key, value in sorted(configs["args"].items(),
|
||||
key=lambda x: int(x[0]))]
|
||||
return configs, interface_arguments
|
||||
|
||||
|
||||
class JobConfigAction(workflows.Action):
|
||||
MAIN_CLASS = "edp.java.main_class"
|
||||
JAVA_OPTS = "edp.java.java_opts"
|
||||
@ -182,9 +209,10 @@ class JobConfigAction(workflows.Action):
|
||||
super(JobConfigAction, self).__init__(request, *args, **kwargs)
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
if job_ex_id is not None:
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
job_ex = saharaclient.job_execution_get(request, job_ex_id)
|
||||
job_configs = job_ex.job_configs
|
||||
job = saharaclient.job_get(request, job_ex.job_id)
|
||||
job_configs, interface_args = _merge_interface_with_configs(
|
||||
job.interface, job_ex.job_configs)
|
||||
edp_configs = {}
|
||||
|
||||
if 'configs' in job_configs:
|
||||
@ -365,6 +393,57 @@ class ClusterGeneralConfig(workflows.Step):
|
||||
return context
|
||||
|
||||
|
||||
class JobExecutionInterfaceConfigAction(workflows.Action):
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(JobExecutionInterfaceConfigAction, self).__init__(
|
||||
request, *args, **kwargs)
|
||||
job_id = (request.GET.get("job_id")
|
||||
or request.POST.get("job"))
|
||||
job = saharaclient.job_get(request, job_id)
|
||||
interface = job.interface or []
|
||||
interface_args = {}
|
||||
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
if job_ex_id is not None:
|
||||
job_ex = saharaclient.job_execution_get(request, job_ex_id)
|
||||
job = saharaclient.job_get(request, job_ex.job_id)
|
||||
job_configs, interface_args = _merge_interface_with_configs(
|
||||
job.interface, job_ex.job_configs)
|
||||
|
||||
for argument in interface:
|
||||
field = forms.CharField(
|
||||
required=argument.get('required'),
|
||||
label=argument['name'],
|
||||
initial=(interface_args.get(argument['id']) or
|
||||
argument.get('default')),
|
||||
help_text=argument.get('description'),
|
||||
widget=forms.TextInput()
|
||||
)
|
||||
self.fields['argument_%s' % argument['id']] = field
|
||||
self.fields['argument_ids'] = forms.CharField(
|
||||
initial=json.dumps({argument['id']: argument['name']
|
||||
for argument in interface}),
|
||||
widget=forms.HiddenInput()
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(JobExecutionInterfaceConfigAction, self).clean()
|
||||
return cleaned_data
|
||||
|
||||
class Meta(object):
|
||||
name = _("Interface Arguments")
|
||||
|
||||
|
||||
class JobExecutionInterfaceConfig(workflows.Step):
|
||||
action_class = JobExecutionInterfaceConfigAction
|
||||
|
||||
def contribute(self, data, context):
|
||||
for k, v in data.items():
|
||||
context[k] = v
|
||||
return context
|
||||
|
||||
|
||||
class LaunchJob(workflows.Workflow):
|
||||
slug = "launch_job"
|
||||
name = _("Launch Job")
|
||||
@ -372,16 +451,22 @@ class LaunchJob(workflows.Workflow):
|
||||
success_message = _("Job launched")
|
||||
failure_message = _("Could not launch job")
|
||||
success_url = "horizon:project:data_processing.job_executions:index"
|
||||
default_steps = (JobExecutionExistingGeneralConfig, JobConfig)
|
||||
default_steps = (JobExecutionExistingGeneralConfig, JobConfig,
|
||||
JobExecutionInterfaceConfig)
|
||||
|
||||
def handle(self, request, context):
|
||||
argument_ids = json.loads(context['argument_ids'])
|
||||
interface = {name: context["argument_" + str(arg_id)]
|
||||
for arg_id, name in argument_ids.items()}
|
||||
|
||||
saharaclient.job_execution_create(
|
||||
request,
|
||||
context["job_general_job"],
|
||||
context["job_general_cluster"],
|
||||
context["job_general_job_input"],
|
||||
context["job_general_job_output"],
|
||||
context["job_config"])
|
||||
context["job_config"],
|
||||
interface)
|
||||
return True
|
||||
|
||||
|
||||
@ -411,11 +496,10 @@ class SelectHadoopPluginAction(t_flows.SelectPluginAction):
|
||||
if job_ex_id is not None:
|
||||
self.fields["job_execution_id"] = forms.ChoiceField(
|
||||
label=_("Job Execution ID"),
|
||||
initial=request.REQUEST.get("job_execution_id"),
|
||||
initial=job_ex_id,
|
||||
widget=forms.HiddenInput(
|
||||
attrs={"class": "hidden_create_field"}))
|
||||
|
||||
job_ex_id = request.REQUEST.get("job_execution_id")
|
||||
job_configs = (
|
||||
saharaclient.job_execution_get(request,
|
||||
job_ex_id).job_configs)
|
||||
@ -459,7 +543,8 @@ class LaunchJobNewCluster(workflows.Workflow):
|
||||
success_url = "horizon:project:data_processing.jobs:index"
|
||||
default_steps = (ClusterGeneralConfig,
|
||||
JobExecutionGeneralConfig,
|
||||
JobConfig)
|
||||
JobConfig,
|
||||
JobExecutionInterfaceConfig)
|
||||
|
||||
def handle(self, request, context):
|
||||
node_groups = None
|
||||
@ -470,6 +555,10 @@ class LaunchJobNewCluster(workflows.Workflow):
|
||||
ct_id = context["cluster_general_cluster_template"] or None
|
||||
user_keypair = context["cluster_general_keypair"] or None
|
||||
|
||||
argument_ids = json.loads(context['argument_ids'])
|
||||
interface = {name: context["argument_" + str(arg_id)]
|
||||
for arg_id, name in argument_ids.items()}
|
||||
|
||||
try:
|
||||
cluster = saharaclient.cluster_create(
|
||||
request,
|
||||
@ -496,7 +585,8 @@ class LaunchJobNewCluster(workflows.Workflow):
|
||||
cluster.id,
|
||||
context["job_general_job_input"],
|
||||
context["job_general_job_output"],
|
||||
context["job_config"])
|
||||
context["job_config"],
|
||||
interface)
|
||||
except Exception:
|
||||
exceptions.handle(request,
|
||||
_("Unable to launch job."))
|
||||
|
@ -0,0 +1,175 @@
|
||||
horizon.job_interface_arguments = {
|
||||
|
||||
argument_template: '' +
|
||||
'<div id_attr="$id">' +
|
||||
'<table class="argument-form table table-striped table-hover" id_attr="$id">' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<input type="button" class="btn btn-danger" id="delete_btn_$id" data-toggle="dropdown" onclick="horizon.job_interface_arguments.delete_interface_argument(this)" value="' + gettext('Remove') + '" />' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<input id="argument_id_$id" value="$id" type="hidden" name="argument_id_$id">' +
|
||||
'<label for="argument_name_$id">' + gettext("Name") + ':</label>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<input id="argument_name_$id" value="$name" type="text" name="argument_name_$id" class="form-control">' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_description_$id">' + gettext("Description") + ':</label>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<input id="argument_description_$id" value="$description" type="text" name="argument_description_$id" class="form-control">' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_mapping_type_$id">' + gettext("Mapping Type") + ':</label>' +
|
||||
'<span class="help-icon" title="" data-placement="top" data-toggle="tooltip" data-original-title="' + gettext("See http://docs.openstack.org/developer/sahara/userdoc/edp.html for definitions.") + '">' +
|
||||
'<span class="fa fa-question-circle"></span>' +
|
||||
'</span>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<select id="argument_mapping_type_$id" selected="$mapping_type" name="argument_mapping_type_$id" class="form-control">' +
|
||||
'<option value="args">' + gettext("Positional Argument") + '</option>' +
|
||||
'<option value="params">' + gettext("Named Parameter") + '</option>' +
|
||||
'<option value="configs">' + gettext("Configuration Value") + '</option>' +
|
||||
'</select>' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_location_$id">' + gettext("Location") + ':</label>' +
|
||||
'<span class="help-icon" title="" data-placement="top" data-toggle="tooltip" data-original-title="' + gettext("For configs and params, type the key name; for args, type the index as an integer, starting from 0.") + '">' +
|
||||
'<span class="fa fa-question-circle"></span>' +
|
||||
'</span>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<input id="argument_location_$id" value="$location" type="text" name="argument_location_$id" class="form-control">' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_value_type_$id">' + gettext("Value Type") + ':</label>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<select id="argument_value_type_$id" selected="$value_type" name="argument_value_type_$id" class="form-control">' +
|
||||
'<option value="string">' + gettext("String") + '</option>' +
|
||||
'<option value="number">' + gettext("Number") + '</option>' +
|
||||
'<option value="data_source">' + gettext("Data Source") + '</option>' +
|
||||
'</select>' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_required_$id">' + gettext("Required?") + ':</label>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<input id="argument_required_$id" type="checkbox" name="argument_required_$id" checked class="form-control">' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td class="col-sm-2 small-padding"></td>' +
|
||||
'<td class="col-sm-2 small-padding">' +
|
||||
'<label for="argument_default_value_$id">' + gettext("Default Value") + ':</label>' +
|
||||
'<span class="help-icon" title="" data-placement="top" data-toggle="tooltip" data-original-title="' + gettext("For data sources, use a data source UUID or a path (as per data source creation.)") + '">' +
|
||||
'<span class="fa fa-question-circle"></span>' +
|
||||
'</span>' +
|
||||
'</td>' +
|
||||
'<td class="col-sm-4 small-padding">' +
|
||||
'<input id="argument_default_value_$id" value="$default_value" type="text" name="argument_default_value_$id" class="form-control">' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'</div>',
|
||||
|
||||
job_interface: null,
|
||||
argument_ids: null,
|
||||
value_type: null,
|
||||
add_argument_button: null,
|
||||
value_type_default: null,
|
||||
|
||||
current_value_type: function() {
|
||||
return this.value_type.find("option:selected").html();
|
||||
},
|
||||
|
||||
mark_argument_element_as_wrong: function(id) {
|
||||
$("#" + id).addClass("error");
|
||||
},
|
||||
|
||||
get_next_argument_id: function() {
|
||||
var max = -1;
|
||||
$(".argument-form").each(function () {
|
||||
max = Math.max(max, parseInt($(this).attr("id_attr")));
|
||||
});
|
||||
return max + 1;
|
||||
},
|
||||
|
||||
set_argument_ids: function() {
|
||||
var ids = [];
|
||||
$(".argument-form").each(function () {
|
||||
var id = parseInt($(this).attr("id_attr"));
|
||||
if (!isNaN(id)) {
|
||||
ids.push(id);
|
||||
}
|
||||
});
|
||||
this.argument_ids.val(JSON.stringify(ids));
|
||||
},
|
||||
|
||||
add_argument_node: function(id, name, description, mapping_type, location, value_type, required, default_value) {
|
||||
var tmp = this.argument_template.
|
||||
replace(/\$id/g, id).
|
||||
replace(/\$name/g, name).
|
||||
replace(/\$description/g, description).
|
||||
replace(/\$mapping_type/g, mapping_type).
|
||||
replace(/\$location/g, location).
|
||||
replace(/\$value_type/g, value_type).
|
||||
replace(/\$required/g, required).
|
||||
replace(/\$default_value/g, default_value);
|
||||
this.job_interface.find("div:last").after(tmp);
|
||||
this.job_interface.show();
|
||||
this.set_argument_ids();
|
||||
},
|
||||
|
||||
add_interface_argument: function() {
|
||||
var value_type = this.current_value_type();
|
||||
if (value_type === this.value_type_default) {
|
||||
return;
|
||||
}
|
||||
this.add_argument_node(this.get_next_argument_id(), "", "", "args", "", value_type, true, "");
|
||||
$(".count-field").change();
|
||||
},
|
||||
|
||||
delete_interface_argument: function(el) {
|
||||
$(el).closest("div").remove();
|
||||
var id = this.get_next_argument_id();
|
||||
if (id === 0) {
|
||||
this.job_interface.hide();
|
||||
}
|
||||
this.set_argument_ids();
|
||||
},
|
||||
|
||||
init_arguments: function() {
|
||||
// This line enables tooltips on this tab to properly display their help text.
|
||||
$("body").tooltip({selector: ".help-icon"});
|
||||
this.job_interface = $("#job_interface_arguments");
|
||||
this.argument_ids = $("#argument_ids");
|
||||
this.value_type = $("#value_type");
|
||||
this.add_argument_button = $("#add_argument_button");
|
||||
this.value_type_default = this.current_value_type();
|
||||
this.value_type.change(function () {
|
||||
if (horizon.job_interface_arguments.current_value_type() === this.value_type_default) {
|
||||
horizon.job_interface_arguments.add_argument_button.addClass("disabled");
|
||||
} else {
|
||||
horizon.job_interface_arguments.add_argument_button.removeClass("disabled");
|
||||
}
|
||||
});
|
||||
this.job_interface.hide();
|
||||
}
|
||||
}
|
@ -126,6 +126,46 @@ def build_node_group_fields(action, name, template, count, serialized=None):
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
|
||||
def build_interface_argument_fields(
|
||||
action, name, description, mapping_type, location, value_type,
|
||||
required, default_value):
|
||||
action.fields[name] = forms.CharField(
|
||||
label=_("Name"),
|
||||
widget=forms.TextInput(),
|
||||
required=True)
|
||||
action.fields[description] = forms.CharField(
|
||||
label=_("Description"),
|
||||
widget=forms.TextInput(),
|
||||
required=False)
|
||||
action.fields[mapping_type] = forms.ChoiceField(
|
||||
label=_("Mapping Type"),
|
||||
widget=forms.Select(),
|
||||
required=True,
|
||||
choices=[("args", _("Positional Argument")),
|
||||
("configs", _("Configuration Value")),
|
||||
("params", _("Named Parameter"))])
|
||||
action.fields[location] = forms.CharField(
|
||||
label=_("Location"),
|
||||
widget=forms.TextInput(),
|
||||
required=True)
|
||||
action.fields[value_type] = forms.ChoiceField(
|
||||
label=_("Value Type"),
|
||||
widget=forms.Select(),
|
||||
required=True,
|
||||
choices=[("string", _("String")),
|
||||
("number", _("Number")),
|
||||
("data_source", _("Data Source"))])
|
||||
action.fields[required] = forms.BooleanField(
|
||||
widget=forms.CheckboxInput(),
|
||||
label=_("Required"),
|
||||
required=False,
|
||||
initial=True)
|
||||
action.fields[default_value] = forms.CharField(
|
||||
label=_("Default Value"),
|
||||
widget=forms.TextInput(),
|
||||
required=False)
|
||||
|
||||
|
||||
def parse_configs_from_context(context, defaults):
|
||||
configs_dict = dict()
|
||||
for key, val in context.items():
|
||||
|
@ -19,6 +19,11 @@ PANEL_DASHBOARD = 'project'
|
||||
PANEL_GROUP = 'data_processing'
|
||||
|
||||
# Python panel class of the PANEL to be added.
|
||||
ADD_PANEL = \
|
||||
('openstack_dashboard.contrib.sahara.'
|
||||
'content.data_processing.jobs.panel.JobsPanel')
|
||||
ADD_PANEL = (
|
||||
'openstack_dashboard.contrib.sahara.'
|
||||
'content.data_processing.jobs.panel.JobsPanel')
|
||||
|
||||
ADD_JS_FILES = [
|
||||
'dashboard/project/data_processing/'
|
||||
'data_processing.job_interface_arguments.js'
|
||||
]
|
||||
|
@ -464,6 +464,7 @@ def data(TEST):
|
||||
"url": "internal-db://80121dea-f8bd-4ad3-bcc7-096f4bfc722d"
|
||||
}
|
||||
],
|
||||
"interface": [],
|
||||
"name": "pigjob",
|
||||
"tenant_id": "429ad8447c2d47bc8e0382d244e1d1df",
|
||||
"type": "Pig",
|
||||
@ -549,6 +550,7 @@ def data(TEST):
|
||||
"configs": {},
|
||||
"params": {}
|
||||
},
|
||||
"interface": {},
|
||||
"job_id": "a077b851-46be-4ad7-93c3-2d83894546ef",
|
||||
"oozie_job_id": "0000000-140604200538581-oozie-hado-W",
|
||||
"output_id": "426fb01c-5c7e-472d-bba2-b1f0fe7e0ede",
|
||||
|
Loading…
Reference in New Issue
Block a user