Sync APIv2 changes into dashboard

- job_id->job_template_id in v2 jobs
- project_id->tenant_id
- Boot from volume enhancements

Story: 2003092
Task: 29741

Change-Id: Ie8e604d73c77a4e7672f87b95ecbe3c1de945293
This commit is contained in:
Jeremy Freudberg 2019-01-10 11:17:51 -05:00
parent 659b1e6a17
commit 29c0205bac
15 changed files with 208 additions and 24 deletions

View File

@ -0,0 +1,12 @@
---
features:
- |
Support for the new boot from volume options introduced in the
Stein release of Sahara is added.
other:
- |
Coinciding with the official stability of Sahara APIv2, operators
should feel especially encouraged to set "data-processing" API
version to "2" in the `OPENSTACK_API_VERSIONS` dictionary found in
Horizon's local_settings.py. As previously stated, some Sahara
features are only exposed through APIv2.

View File

@ -171,7 +171,10 @@ def nodegroup_template_create(request, name, plugin_name, hadoop_version,
is_public=None,
is_protected=None,
volume_mount_prefix=None,
boot_from_volume=None):
boot_from_volume=None,
boot_volume_type=None,
boot_volume_availability_zone=None,
boot_volume_local_to_instance=None):
payload = dict(
name=name,
@ -200,6 +203,13 @@ def nodegroup_template_create(request, name, plugin_name, hadoop_version,
if VERSIONS.active == '2':
payload['plugin_version'] = hadoop_version
payload['boot_from_volume'] = boot_from_volume
payload['boot_volume_type'] = boot_volume_type
payload['boot_volume_availability_zone'] = (
boot_volume_availability_zone
)
payload['boot_volume_local_to_instance'] = (
boot_volume_local_to_instance
)
else:
payload['hadoop_version'] = hadoop_version
@ -243,7 +253,10 @@ def nodegroup_template_update(request, ngt_id, name, plugin_name,
is_protected=None,
is_public=None,
image_id=None,
boot_from_volume=None):
boot_from_volume=None,
boot_volume_type=None,
boot_volume_availability_zone=None,
boot_volume_local_to_instance=None):
payload = dict(
ng_template_id=ngt_id,
@ -272,6 +285,14 @@ def nodegroup_template_update(request, ngt_id, name, plugin_name,
if VERSIONS.active == '2':
payload['plugin_version'] = hadoop_version
payload['boot_from_volume'] = boot_from_volume
payload['boot_volume_type'] = boot_volume_type
payload['boot_volume_availability_zone'] = (
boot_volume_availability_zone
)
payload['boot_volume_local_to_instance'] = (
boot_volume_local_to_instance
)
else:
payload['hadoop_version'] = hadoop_version
@ -696,11 +717,17 @@ def job_execution_list(request, search_opts=None, marker=None, limit=None):
job_dict = {j.id: j for j in _job_list(new_request)}
cluster_dict = {c.id: c for c in _cluster_list(new_request)}
def _find_jt_id(jex_obj):
try:
return jex_obj.job_template_id # typical APIv2
except AttributeError:
return jex_obj.job_id # APIv1.1, older APIv2
resolved_job_execution_list = [
_resolve_job_execution_names(
job_execution,
cluster_dict.get(job_execution.cluster_id),
job_dict.get(job_execution.job_id))
job_dict.get(_find_jt_id(job_execution)))
for job_execution in job_execution_list
]
@ -719,7 +746,11 @@ def job_execution_get(request, jex_id):
jex = getattr(sahara, je_manager).get(obj_id=jex_id)
cluster = safe_call(client(request).clusters.get, jex.cluster_id)
job = safe_call(getattr(sahara, jt_manager).get, jex.job_id)
try:
jt_id = jex.job_template_id # typical APIv2
except AttributeError:
jt_id = jex.job_id # APIv1.1, older APIv2
job = safe_call(getattr(sahara, jt_manager).get, jt_id)
return _resolve_job_execution_names(jex, cluster, job)

View File

@ -98,10 +98,16 @@ class GeneralTab(tabs.Tab):
security_groups = helpers.get_security_groups(
request, template.security_groups)
if getattr(template, 'boot_from_volume', None) is None:
show_bfv = False
else:
show_bfv = True
return {"template": template, "flavor": flavor,
"floating_ip_pool_name": floating_ip_pool_name,
"base_image_name": base_image_name,
"security_groups": security_groups}
"security_groups": security_groups,
"show_bfv": show_bfv}
def _get_floating_ip_pool_name(self, request, pool_id):
pools = [pool for pool in neutron.floating_ip_pools_list(

View File

@ -78,7 +78,7 @@ class GeneralConfigAction(workflows.Action):
)
storage = forms.ChoiceField(
label=_("Storage location"),
label=_("Attached storage location"),
help_text=_("Choose a storage location"),
choices=[],
widget=forms.Select(attrs={
@ -191,13 +191,51 @@ class GeneralConfigAction(workflows.Action):
_("node group template"))
if saharaclient.VERSIONS.active == '2':
self.fields['boot_from_volume'] = forms.BooleanField(
label=_("Boot From Volume"),
help_text=_("If selected, the node group instance will be "
"booted from volume"),
self.fields['boot_storage'] = forms.ChoiceField(
label=_("Boot storage location"),
help_text=_("Choose a boot mode"),
choices=storage_choices(request),
widget=forms.Select(attrs={
"class": "boot_storage_field switchable",
'data-slug': 'boot_storage_loc'
}))
self.fields['boot_volume_type'] = forms.ChoiceField(
label=_("Boot volume type"),
required=False,
widget=forms.CheckboxInput(),
initial=False)
widget=forms.Select(attrs={
"class": "boot_volume_type_field switched",
"data-switch-on": "boot_storage_loc",
"data-boot_storage_loc-cinder_volume":
_('Boot volume type')
})
)
self.fields['boot_volume_local_to_instance'] = forms.BooleanField(
label=_("Boot volume local to instance"),
required=False,
help_text=_("Boot volume locality"),
widget=forms.CheckboxInput(attrs={
"class": "boot_volume_local_to_instance_field switched",
"data-switch-on": "boot_storage_loc",
"data-boot_storage_loc-cinder_volume":
_('Boot volume local to instance')
})
)
self.fields['boot_volume_availability_zone'] = forms.ChoiceField(
label=_("Boot volume availability Zone"),
choices=self.populate_volumes_availability_zone_choices(
request, None),
help_text=_("Create boot volume in this availability zone."),
required=False,
widget=forms.Select(attrs={
"class": "boot_volume_availability_zone_field switched",
"data-switch-on": "boot_storage_loc",
"data-boot_storage_loc-cinder_volume":
_('Boot volume availability zone')
})
)
self.fields["plugin_name"] = forms.CharField(
widget=forms.HiddenInput(),
@ -234,6 +272,10 @@ class GeneralConfigAction(workflows.Action):
[(type.name, type.name)
for type in volume_types]
if saharaclient.VERSIONS.active == '2':
self.fields['boot_volume_type'].choices = (
self.fields['volume_type'].choices)
def populate_flavor_choices(self, request, context):
flavors = nova_utils.flavor_list(request)
if flavors:
@ -556,10 +598,23 @@ class ConfigureNodegroupTemplate(workflow_helpers.ServiceParametersWorkflow,
image_id = context["general_image"] or None
if saharaclient.VERSIONS.active == '2':
boot_from_volume = context["general_boot_from_volume"]
if (saharaclient.VERSIONS.active == '2'
and context["general_boot_storage"] == "cinder_volume"):
boot_from_volume = True
boot_volume_type = (
context["general_boot_volume_type"] or None
)
boot_volume_availability_zone = (
context["general_boot_volume_availability_zone"] or None
)
boot_volume_local_to_instance = (
context["general_boot_volume_local_to_instance"]
)
else:
boot_from_volume = None
boot_volume_type = None
boot_volume_availability_zone = None
boot_volume_local_to_instance = None
ngt = saharaclient.nodegroup_template_create(
request,
@ -585,6 +640,9 @@ class ConfigureNodegroupTemplate(workflow_helpers.ServiceParametersWorkflow,
is_public=context['general_is_public'],
is_protected=context['general_is_protected'],
boot_from_volume=boot_from_volume,
boot_volume_type=boot_volume_type,
boot_volume_availability_zone=boot_volume_availability_zone,
boot_volume_local_to_instance=boot_volume_local_to_instance,
image_id=image_id)
hlps = helpers.Helpers(request)

View File

@ -105,9 +105,18 @@ class EditNodegroupTemplate(copy_flow.CopyNodegroupTemplate):
is_protected=context['general_is_protected'],
image_id=image_id)
if saharaclient.VERSIONS.active == '2':
args_dict['boot_from_volume'] = (
context['general_boot_from_volume'])
if (saharaclient.VERSIONS.active == '2'
and context["general_boot_storage"] == "cinder_volume"):
args_dict['boot_from_volume'] = True
args_dict['boot_volume_type'] = (
context["general_boot_volume_type"] or None
)
args_dict['boot_volume_availability_zone'] = (
context["general_boot_volume_availability_zone"] or None
)
args_dict['boot_volume_local_to_instance'] = (
context["general_boot_volume_local_to_instance"]
)
saharaclient.nodegroup_template_update(**args_dict)

View File

@ -5,7 +5,11 @@
<dt>{% trans "Name" %}</dt>
<dd>{{ template.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if template.tenant_id %}
<dd>{{ template.tenant_id }}</dd>
{% else %}
<dd>{{ template.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ template.id }}</dd>
<dt>{% trans "Description" %}</dt>

View File

@ -5,7 +5,11 @@
<dt>{% trans "Name" %}</dt>
<dd>{{ cluster.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if cluster.tenant_id %}
<dd>{{ cluster.tenant_id }}</dd>
{% else %}
<dd>{{ cluster.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ cluster.id }}</dd>
<dt>{% trans "Description" %}</dt>

View File

@ -4,8 +4,12 @@
<dl class="dl-horizontal">
<dt>{% trans "Name" %}</dt>
<dd>{{ template.name }}</dd>
<dt>{% trans "Project Id" %}</dt>
<dt>{% trans "Project ID" %}</dt>
{% if template.tenant_id %}
<dd>{{ template.tenant_id }}</dd>
{% else %}
<dd>{{ template.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ template.id }}</dd>
<dt>{% trans "Description" %}</dt>
@ -60,8 +64,18 @@
</dl>
<dl class="dl-horizontal">
{% if show_bfv %}
<dt>{% trans "Boot from Volume" %}</dt>
<dd>{{ template.boot_from_volume }}</dd>
{% if template.boot_from_volume %}
<dt>{% trans "Boot Volume type" %}</dt>
<dd>{{ template.boot_volume_type }}</dd>
<dt>{% trans "Boot Volume AZ" %}</dt>
<dd>{{ template.boot_volume_availability_zone }}</dd>
<dt>{% trans "Boot Volume locality" %}</dt>
<dd>{{ template.boot_volume_local_to_instance }}</dd>
{% endif %}
{% endif %}
</dl>
<dl class="dl-horizontal">

View File

@ -239,7 +239,11 @@ class JobConfigAction(workflows.Action):
job_ex_id = req.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)
try:
jt_id = job_ex.job_template_id # typical APIv2
except AttributeError:
jt_id = job_ex.job_id # APIv1.1, older APIv2
job = saharaclient.job_get(request, jt_id)
job_configs, interface_args = _merge_interface_with_configs(
job.interface, job_ex.job_configs)
edp_configs = {}
@ -466,7 +470,11 @@ class JobExecutionInterfaceConfigAction(workflows.Action):
job_ex_id = req.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)
try:
jt_id = job_ex.job_template_id # typical APIv2
except AttributeError:
jt_id = job_ex.job_id # APIv1.1, older APIv2
job = saharaclient.job_get(request, jt_id)
job_configs, interface_args = _merge_interface_with_configs(
job.interface, job_ex.job_configs)

View File

@ -92,7 +92,11 @@ class ReLaunchJobExistingCluster(j_t.ChoosePlugin):
def get_link_url(self, datum):
base_url = reverse(self.url)
params = http.urlencode({'job_id': datum.job_id,
try:
job_template_id = datum.job_template_id # typical APIv2
except AttributeError:
job_template_id = datum.job_id # APIv1.1, older APIv2
params = http.urlencode({'job_id': job_template_id,
'job_execution_id': datum.id})
return "?".join([base_url, params])
@ -164,9 +168,15 @@ class JobsTable(sahara_table.SaharaPaginateTabbedTable):
@staticmethod
def link(job_execution):
if job_execution.job_name:
try:
# typical APIv2
job_template_id = job_execution.job_template_id
except AttributeError:
# APIv1.1, older APIv2
job_template_id = job_execution.job_id
return reverse("horizon:project:data_processing."
"jobs:jt-details",
args=(http.urlquote(job_execution.job_id),))
args=(http.urlquote(job_template_id),))
else:
# No link should be generated for a deleted Job.
return None

View File

@ -103,6 +103,10 @@ class GeneralTab(tabs.Tab):
def get_object_names(self, job_ex, request):
object_names = {}
try:
job_template_id = job_ex.job_template_id # typical APIv2
except AttributeError:
job_template_id = job_ex.job_id # APIv1.1, older APIv2
obj_names_map = {'input_name': {'obj': 'data_source_get',
'obj_id': job_ex.input_id},
'output_name': {'obj': 'data_source_get',
@ -110,7 +114,7 @@ class GeneralTab(tabs.Tab):
'cluster_name': {'obj': 'cluster_get',
'obj_id': job_ex.cluster_id},
'job_name': {'obj': 'job_get',
'obj_id': job_ex.job_id}}
'obj_id': job_template_id}}
for item in obj_names_map:
object_names[item] = (
self.get_object_name(obj_names_map[item]['obj_id'],

View File

@ -5,7 +5,11 @@
<dt>{% trans "Name" %}</dt>
<dd>{{ data_source.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if data_source.tenant_id %}
<dd>{{ data_source.tenant_id }}</dd>
{% else %}
<dd>{{ data_source.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ data_source.id }}</dd>
<dt>{% trans "Type" %}</dt>

View File

@ -5,7 +5,11 @@
<dt>{% trans "Name" %}</dt>
<dd>{{ job_binary.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if job_binary.tenant_id %}
<dd>{{ job_binary.tenant_id }}</dd>
{% else %}
<dd>{{ job_binary.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ job_binary.id }}</dd>
<dt>{% trans "URL" %}</dt>

View File

@ -5,7 +5,11 @@
<dt>{% trans "Name" %}</dt>
<dd>{{ job.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if job.tenant_id %}
<dd>{{ job.tenant_id }}</dd>
{% else %}
<dd>{{ job.project_id }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ job.id }}</dd>
<dt>{% trans "Type" %}</dt>

View File

@ -7,9 +7,21 @@
<dt>{% trans "ID" %}</dt>
<dd>{{ job_execution.id }}</dd>
<dt>{% trans "Project ID" %}</dt>
{% if job_execution.tenant_id %}
<dd>{{ job_execution.tenant_id }}</dd>
{% else %}
<dd>{{ job_execution.project_id }}</dd>
{% endif %}
<dt>{% trans "Job Template" %}</dt>
<dd><a href="{% url 'horizon:project:data_processing.jobs:jt-details' job_execution.job_id %}">{{ object_names.job_name }}</a></dd>
<dd>
{% if job_execution.job_id %}
<a href="{% url 'horizon:project:data_processing.jobs:jt-details' job_execution.job_id %}">
{% else %}
<a href="{% url 'horizon:project:data_processing.jobs:jt-details' job_execution.job_template_id %}">
{% endif %}
{{ object_names.job_name }}
</a>
</dd>
<dt>{% trans "Public" %}</dt>
<dd>{{ job_execution.is_public|yesno }}</dd>
<dt>{% trans "Protected" %}</dt>