From 29c0205bac4276a8e9d08efb03e040c7cc287b10 Mon Sep 17 00:00:00 2001 From: Jeremy Freudberg Date: Thu, 10 Jan 2019 11:17:51 -0500 Subject: [PATCH] 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 --- .../more-apiv2-features-7e02b39be1b875fd.yaml | 12 +++ sahara_dashboard/api/sahara.py | 39 +++++++++- .../clusters/nodegroup_templates/tabs.py | 8 +- .../nodegroup_templates/workflows/create.py | 76 ++++++++++++++++--- .../nodegroup_templates/workflows/edit.py | 15 +++- .../templates/cluster_templates/_details.html | 4 + .../clusters/templates/clusters/_details.html | 4 + .../nodegroup_templates/_details.html | 16 +++- .../jobs/job_templates/workflows/launch.py | 12 ++- .../data_processing/jobs/jobs/tables.py | 14 +++- .../content/data_processing/jobs/jobs/tabs.py | 6 +- .../jobs/templates/data_sources/_details.html | 4 + .../jobs/templates/job_binaries/_details.html | 4 + .../templates/job_templates/_details.html | 4 + .../jobs/templates/jobs/_details.html | 14 +++- 15 files changed, 208 insertions(+), 24 deletions(-) create mode 100644 releasenotes/notes/more-apiv2-features-7e02b39be1b875fd.yaml diff --git a/releasenotes/notes/more-apiv2-features-7e02b39be1b875fd.yaml b/releasenotes/notes/more-apiv2-features-7e02b39be1b875fd.yaml new file mode 100644 index 00000000..0a3b1d64 --- /dev/null +++ b/releasenotes/notes/more-apiv2-features-7e02b39be1b875fd.yaml @@ -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. diff --git a/sahara_dashboard/api/sahara.py b/sahara_dashboard/api/sahara.py index 2a3e5237..a96597ad 100644 --- a/sahara_dashboard/api/sahara.py +++ b/sahara_dashboard/api/sahara.py @@ -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) diff --git a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/tabs.py b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/tabs.py index b82283af..fe955030 100644 --- a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/tabs.py +++ b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/tabs.py @@ -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( diff --git a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/create.py b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/create.py index 9de56b18..17db11b1 100644 --- a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/create.py +++ b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/create.py @@ -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) diff --git a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/edit.py b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/edit.py index cee76255..1646e3f5 100644 --- a/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/edit.py +++ b/sahara_dashboard/content/data_processing/clusters/nodegroup_templates/workflows/edit.py @@ -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) diff --git a/sahara_dashboard/content/data_processing/clusters/templates/cluster_templates/_details.html b/sahara_dashboard/content/data_processing/clusters/templates/cluster_templates/_details.html index c31346e2..96878217 100644 --- a/sahara_dashboard/content/data_processing/clusters/templates/cluster_templates/_details.html +++ b/sahara_dashboard/content/data_processing/clusters/templates/cluster_templates/_details.html @@ -5,7 +5,11 @@
{% trans "Name" %}
{{ template.name }}
{% trans "Project ID" %}
+ {% if template.tenant_id %}
{{ template.tenant_id }}
+ {% else %} +
{{ template.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ template.id }}
{% trans "Description" %}
diff --git a/sahara_dashboard/content/data_processing/clusters/templates/clusters/_details.html b/sahara_dashboard/content/data_processing/clusters/templates/clusters/_details.html index 9e3165f7..901738ae 100644 --- a/sahara_dashboard/content/data_processing/clusters/templates/clusters/_details.html +++ b/sahara_dashboard/content/data_processing/clusters/templates/clusters/_details.html @@ -5,7 +5,11 @@
{% trans "Name" %}
{{ cluster.name }}
{% trans "Project ID" %}
+ {% if cluster.tenant_id %}
{{ cluster.tenant_id }}
+ {% else %} +
{{ cluster.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ cluster.id }}
{% trans "Description" %}
diff --git a/sahara_dashboard/content/data_processing/clusters/templates/nodegroup_templates/_details.html b/sahara_dashboard/content/data_processing/clusters/templates/nodegroup_templates/_details.html index cb99b8e1..09cdd613 100644 --- a/sahara_dashboard/content/data_processing/clusters/templates/nodegroup_templates/_details.html +++ b/sahara_dashboard/content/data_processing/clusters/templates/nodegroup_templates/_details.html @@ -4,8 +4,12 @@
{% trans "Name" %}
{{ template.name }}
-
{% trans "Project Id" %}
+
{% trans "Project ID" %}
+ {% if template.tenant_id %}
{{ template.tenant_id }}
+ {% else %} +
{{ template.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ template.id }}
{% trans "Description" %}
@@ -60,8 +64,18 @@
+ {% if show_bfv %}
{% trans "Boot from Volume" %}
{{ template.boot_from_volume }}
+ {% if template.boot_from_volume %} +
{% trans "Boot Volume type" %}
+
{{ template.boot_volume_type }}
+
{% trans "Boot Volume AZ" %}
+
{{ template.boot_volume_availability_zone }}
+
{% trans "Boot Volume locality" %}
+
{{ template.boot_volume_local_to_instance }}
+ {% endif %} + {% endif %}
diff --git a/sahara_dashboard/content/data_processing/jobs/job_templates/workflows/launch.py b/sahara_dashboard/content/data_processing/jobs/job_templates/workflows/launch.py index 89c32fd6..9bde870e 100644 --- a/sahara_dashboard/content/data_processing/jobs/job_templates/workflows/launch.py +++ b/sahara_dashboard/content/data_processing/jobs/job_templates/workflows/launch.py @@ -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) diff --git a/sahara_dashboard/content/data_processing/jobs/jobs/tables.py b/sahara_dashboard/content/data_processing/jobs/jobs/tables.py index 952b322c..ba8ecf5c 100644 --- a/sahara_dashboard/content/data_processing/jobs/jobs/tables.py +++ b/sahara_dashboard/content/data_processing/jobs/jobs/tables.py @@ -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 diff --git a/sahara_dashboard/content/data_processing/jobs/jobs/tabs.py b/sahara_dashboard/content/data_processing/jobs/jobs/tabs.py index 420aa76e..bf604bd8 100644 --- a/sahara_dashboard/content/data_processing/jobs/jobs/tabs.py +++ b/sahara_dashboard/content/data_processing/jobs/jobs/tabs.py @@ -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'], diff --git a/sahara_dashboard/content/data_processing/jobs/templates/data_sources/_details.html b/sahara_dashboard/content/data_processing/jobs/templates/data_sources/_details.html index ed301f4f..a8396f61 100644 --- a/sahara_dashboard/content/data_processing/jobs/templates/data_sources/_details.html +++ b/sahara_dashboard/content/data_processing/jobs/templates/data_sources/_details.html @@ -5,7 +5,11 @@
{% trans "Name" %}
{{ data_source.name }}
{% trans "Project ID" %}
+ {% if data_source.tenant_id %}
{{ data_source.tenant_id }}
+ {% else %} +
{{ data_source.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ data_source.id }}
{% trans "Type" %}
diff --git a/sahara_dashboard/content/data_processing/jobs/templates/job_binaries/_details.html b/sahara_dashboard/content/data_processing/jobs/templates/job_binaries/_details.html index ec4c7949..bae13483 100644 --- a/sahara_dashboard/content/data_processing/jobs/templates/job_binaries/_details.html +++ b/sahara_dashboard/content/data_processing/jobs/templates/job_binaries/_details.html @@ -5,7 +5,11 @@
{% trans "Name" %}
{{ job_binary.name }}
{% trans "Project ID" %}
+ {% if job_binary.tenant_id %}
{{ job_binary.tenant_id }}
+ {% else %} +
{{ job_binary.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ job_binary.id }}
{% trans "URL" %}
diff --git a/sahara_dashboard/content/data_processing/jobs/templates/job_templates/_details.html b/sahara_dashboard/content/data_processing/jobs/templates/job_templates/_details.html index 0abc80ea..76cd78dd 100644 --- a/sahara_dashboard/content/data_processing/jobs/templates/job_templates/_details.html +++ b/sahara_dashboard/content/data_processing/jobs/templates/job_templates/_details.html @@ -5,7 +5,11 @@
{% trans "Name" %}
{{ job.name }}
{% trans "Project ID" %}
+ {% if job.tenant_id %}
{{ job.tenant_id }}
+ {% else %} +
{{ job.project_id }}
+ {% endif %}
{% trans "ID" %}
{{ job.id }}
{% trans "Type" %}
diff --git a/sahara_dashboard/content/data_processing/jobs/templates/jobs/_details.html b/sahara_dashboard/content/data_processing/jobs/templates/jobs/_details.html index 237ba7ec..46148591 100644 --- a/sahara_dashboard/content/data_processing/jobs/templates/jobs/_details.html +++ b/sahara_dashboard/content/data_processing/jobs/templates/jobs/_details.html @@ -7,9 +7,21 @@
{% trans "ID" %}
{{ job_execution.id }}
{% trans "Project ID" %}
+ {% if job_execution.tenant_id %}
{{ job_execution.tenant_id }}
+ {% else %} +
{{ job_execution.project_id }}
+ {% endif %}
{% trans "Job Template" %}
-
{{ object_names.job_name }}
+
+ {% if job_execution.job_id %} + + {% else %} + + {% endif %} + {{ object_names.job_name }} + +
{% trans "Public" %}
{{ job_execution.is_public|yesno }}
{% trans "Protected" %}