From 79c184ddfe08ed461818583499d933ef7bca4087 Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Wed, 26 Sep 2018 14:07:42 -0400 Subject: [PATCH] Distributed Cloud Patching Dashboard Introduction of software management panel to distributed cloud admin dashboad Change-Id: Id2933c1e2dec0492cccf4552388e6fca9a371125 Story: 2002833 Task: 22752 Signed-off-by: Tyler Smith --- starlingx-dashboard/centos/build_srpm.data | 2 +- .../starlingx_dashboard/api/dc_manager.py | 242 ++++++++----- .../admin/software_management/panel.py | 4 + .../admin/software_management/views.py | 3 +- .../dc_software_management/__init__.py | 0 .../dc_admin/dc_software_management/forms.py | 185 ++++++++++ .../dc_admin/dc_software_management/panel.py | 30 ++ .../dc_admin/dc_software_management/tables.py | 327 ++++++++++++++++++ .../dc_admin/dc_software_management/tabs.py | 93 +++++ .../_cloud_patch_config.html | 5 + .../_cloud_patch_orchestration.html | 29 ++ .../_create_cloud_patch_config.html | 28 ++ .../_create_cloud_patch_strategy.html | 25 ++ .../_detail_patches.html | 54 +++ .../_edit_cloud_patch_config.html | 28 ++ .../dc_software_management/_patches.html | 10 + .../dc_software_management/_upload_patch.html | 27 ++ .../create_cloud_patch_config.html | 11 + .../create_cloud_patch_strategy.html | 11 + .../edit_cloud_patch_config.html | 11 + .../dc_software_management/index.html | 28 ++ .../dc_software_management/upload_patch.html | 11 + .../dc_admin/dc_software_management/urls.py | 35 ++ .../dc_admin/dc_software_management/views.py | 94 +++++ ...tarlingx_dc_admin_cloud_overview_panel.py} | 0 ..._WRS_dc_admin_software_management_panel.py | 10 + .../starlingx_dashboard/exceptions.py | 2 + 27 files changed, 1224 insertions(+), 81 deletions(-) create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/__init__.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/forms.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/panel.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tables.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tabs.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_config.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_orchestration.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_config.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_strategy.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_detail_patches.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_edit_cloud_patch_config.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_patches.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_upload_patch.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_config.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_strategy.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/edit_cloud_patch_config.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/index.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/upload_patch.html create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/urls.py create mode 100755 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/views.py rename starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/{_2210_starlingx_dc_admin_cloud_overview_panel.py => _2211_starlingx_dc_admin_cloud_overview_panel.py} (100%) create mode 100644 starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2212_WRS_dc_admin_software_management_panel.py diff --git a/starlingx-dashboard/centos/build_srpm.data b/starlingx-dashboard/centos/build_srpm.data index 35d217d8..cb45a03a 100644 --- a/starlingx-dashboard/centos/build_srpm.data +++ b/starlingx-dashboard/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="starlingx-dashboard" -TIS_PATCH_VER=12 +TIS_PATCH_VER=13 diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/dc_manager.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/dc_manager.py index 3cd1a2e1..de191f39 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/dc_manager.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/dc_manager.py @@ -1,79 +1,163 @@ -# 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. -# -# Copyright (c) 2017 Wind River Systems, Inc. -# - -import logging - -from dcmanagerclient.api.v1 import client - -from horizon.utils.memoized import memoized # noqa - -from openstack_dashboard.api import base - -LOG = logging.getLogger(__name__) - - -@memoized -def dcmanagerclient(request): - endpoint = base.url_for(request, 'dcmanager', 'adminURL') - c = client.Client(project_id=request.user.project_id, - user_id=request.user.id, - auth_token=request.user.token.id, - dcmanager_url=endpoint) - return c - - -class Summary(base.APIResourceWrapper): - _attrs = ['name', 'critical', 'major', 'minor', 'warnings', 'status'] - - -def alarm_summary_list(request): - summaries = dcmanagerclient(request).alarm_manager.list_alarms() - return [Summary(summary) for summary in summaries] - - -class Subcloud(base.APIResourceWrapper): - _attrs = ['subcloud_id', 'name', 'description', 'location', - 'software_version', 'management_subnet', 'management_state', - 'availability_status', 'management_start_ip', - 'management_end_ip', 'management_gateway_ip', - 'systemcontroller_gateway_ip', 'created_at', 'updated_at', - 'sync_status', 'endpoint_sync_status', ] - - -def subcloud_list(request): - subclouds = dcmanagerclient(request).subcloud_manager.list_subclouds() - return [Subcloud(subcloud) for subcloud in subclouds] - - -def subcloud_create(request, data): - return dcmanagerclient(request).subcloud_manager.add_subcloud( - **data.get('data')) - - -def subcloud_update(request, subcloud_id, changes): - response = dcmanagerclient(request).subcloud_manager.update_subcloud( - subcloud_id, **changes.get('updated')) - # Updating returns a list of subclouds for some reason - return [Subcloud(subcloud) for subcloud in response] - - -def subcloud_delete(request, subcloud_id): - return dcmanagerclient(request).subcloud_manager.delete_subcloud( - subcloud_id) - - -def subcloud_generate_config(request, subcloud_id, data): - return dcmanagerclient(request).subcloud_manager.generate_config_subcloud( - subcloud_id, **data) +# 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. +# +# Copyright (c) 2017-2018 Wind River Systems, Inc. +# + +import logging + +from dcmanagerclient.api.v1 import client +from dcmanagerclient.exceptions import APIException + +from horizon.utils.memoized import memoized # noqa + +from openstack_dashboard.api import base + +LOG = logging.getLogger(__name__) + + +DEFAULT_CONFIG_NAME = "all clouds default" + + +@memoized +def dcmanagerclient(request): + endpoint = base.url_for(request, 'dcmanager', 'adminURL') + c = client.Client(project_id=request.user.project_id, + user_id=request.user.id, + auth_token=request.user.token.id, + dcmanager_url=endpoint) + return c + + +class Summary(base.APIResourceWrapper): + _attrs = ['name', 'critical', 'major', 'minor', 'warnings', 'status'] + + +def alarm_summary_list(request): + summaries = dcmanagerclient(request).alarm_manager.list_alarms() + return [Summary(summary) for summary in summaries] + + +class Subcloud(base.APIResourceWrapper): + _attrs = ['subcloud_id', 'name', 'description', 'location', + 'software_version', 'management_subnet', 'management_state', + 'availability_status', 'management_start_ip', + 'management_end_ip', 'management_gateway_ip', + 'systemcontroller_gateway_ip', 'created_at', 'updated_at', + 'sync_status', 'endpoint_sync_status', ] + + +def subcloud_list(request): + subclouds = dcmanagerclient(request).subcloud_manager.list_subclouds() + return [Subcloud(subcloud) for subcloud in subclouds] + + +def subcloud_create(request, data): + return dcmanagerclient(request).subcloud_manager.add_subcloud( + **data.get('data')) + + +def subcloud_update(request, subcloud_id, changes): + response = dcmanagerclient(request).subcloud_manager.update_subcloud( + subcloud_id, **changes.get('updated')) + # Updating returns a list of subclouds for some reason + return [Subcloud(subcloud) for subcloud in response] + + +def subcloud_delete(request, subcloud_id): + return dcmanagerclient(request).subcloud_manager.delete_subcloud( + subcloud_id) + + +def subcloud_generate_config(request, subcloud_id, data): + return dcmanagerclient(request).subcloud_manager.generate_config_subcloud( + subcloud_id, **data) + + +class Strategy(base.APIResourceWrapper): + _attrs = ['subcloud_apply_type', 'max_parallel_subclouds', + 'stop_on_failure', 'state', 'created_at', 'updated_at'] + + +def get_strategy(request): + try: + response = dcmanagerclient(request).sw_update_manager.\ + patch_strategy_detail() + except APIException as e: + if e.error_code == 404: + return None + else: + raise e + + if response and len(response): + return Strategy(response[0]) + + +def strategy_create(request, data): + response = dcmanagerclient(request).sw_update_manager.\ + create_patch_strategy(**data) + return Strategy(response) + + +def strategy_apply(request): + return dcmanagerclient(request).sw_update_manager.apply_patch_strategy() + + +def strategy_abort(request): + return dcmanagerclient(request).sw_update_manager.abort_patch_strategy() + + +def strategy_delete(request): + return dcmanagerclient(request).sw_update_manager.delete_patch_strategy() + + +class Step(base.APIResourceWrapper): + _attrs = ['cloud', 'stage', 'state', 'details', 'started_at', + 'finished_at'] + + +def step_list(request): + response = dcmanagerclient(request).strategy_step_manager.\ + list_strategy_steps() + return [Step(step) for step in response] + + +class Config(base.APIResourceWrapper): + _attrs = ['cloud', 'storage_apply_type', 'compute_apply_type', + 'max_parallel_computes', 'alarm_restriction_type', + 'default_instance_action'] + + +def config_list(request): + response = dcmanagerclient(request).sw_update_options_manager.\ + sw_update_options_list() + return [Config(config) for config in response] + + +def config_update(request, subcloud, data): + response = dcmanagerclient(request).sw_update_options_manager.\ + sw_update_options_update(subcloud, **data) + return Config(response) + + +def config_delete(request, subcloud): + return dcmanagerclient(request).sw_update_options_manager.\ + sw_update_options_delete(subcloud) + + +def config_get(request, subcloud): + if subcloud == DEFAULT_CONFIG_NAME: + subcloud = None + response = dcmanagerclient(request).sw_update_options_manager.\ + sw_update_options_detail(subcloud) + if response and len(response): + return Config(response[0]) diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/panel.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/panel.py index e1c533e9..56e55548 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/panel.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/panel.py @@ -19,12 +19,16 @@ class SoftwareManagement(horizon.Panel): def allowed(self, context): if not base.is_service_enabled(context['request'], 'platform'): return False + elif context['request'].user.services_region == 'SystemController': + return False else: return super(SoftwareManagement, self).allowed(context) def nav(self, context): if not base.is_service_enabled(context['request'], 'platform'): return False + elif context['request'].user.services_region == 'SystemController': + return False else: return True diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/views.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/views.py index a8b1643c..e52d6c0a 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/views.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/software_management/views.py @@ -42,6 +42,7 @@ class IndexView(tabs.TabbedTableView): class DetailPatchView(views.HorizonTemplateView): template_name = 'admin/software_management/_detail_patches.html' + failure_url = 'horizon:admin:software_management:index' page_title = 'Patch Detail' def get_context_data(self, **kwargs): @@ -59,7 +60,7 @@ class DetailPatchView(views.HorizonTemplateView): patch.requires_display = "%s" % "\n".join( filter(None, patch.requires)) except Exception: - redirect = reverse('horizon:admin:software_management:index') + redirect = reverse(self.failure_url) exceptions.handle(self.request, _('Unable to retrieve details for ' 'patch "%s".') % patch_id, diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/__init__.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/forms.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/forms.py new file mode 100755 index 00000000..9d5b5363 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/forms.py @@ -0,0 +1,185 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import logging + +from dcmanagerclient import exceptions as exc + +from django.core.urlresolvers import reverse # noqa +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import messages + +from starlingx_dashboard import api +from starlingx_dashboard.dashboards.admin.software_management.forms \ + import UploadPatchForm as AdminPatchForm + +LOG = logging.getLogger(__name__) + + +class UploadPatchForm(AdminPatchForm): + failure_url = 'horizon:dc_admin:dc_software_management:index' + + +class CreateCloudPatchStrategyForm(forms.SelfHandlingForm): + failure_url = 'horizon:dc_admin:dc_software_management:index' + + SUBCLOUD_APPLY_TYPES = ( + ('parallel', _("Parallel")), + ('serial', _("Serial")), + ) + + subcloud_apply_type = forms.ChoiceField( + label=_("Subcloud Apply Type"), + required=True, + choices=SUBCLOUD_APPLY_TYPES, + widget=forms.Select()) + + max_parallel_subclouds = forms.IntegerField( + label=_("Maximum Parallel Subclouds"), + initial=20, + min_value=2, + max_value=100, + required=True, + error_messages={'invalid': _('Maximum Parallel Subclouds must be ' + 'between 2 and 100.')}, + widget=forms.TextInput()) + + stop_on_failure = forms.BooleanField( + label=_("Stop on Failure"), + required=False, + initial=True, + help_text=_("Determines whether patch orchestration failure in a " + "subcloud prevents application to subsequent subclouds")) + + def handle(self, request, data): + try: + # convert keys to use dashes + for k in data.keys(): + if '_' in k: + data[k.replace('_', '-')] = data[k] + del data[k] + + data['stop-on-failure'] = str(data['stop-on-failure']).lower() + + response = api.dc_manager.strategy_create(request, data) + if not response: + messages.error(request, "Strategy creation failed") + except Exception: + redirect = reverse(self.failure_url) + exceptions.handle(request, "Strategy creation failed", + redirect=redirect) + return True + + +class CreateCloudPatchConfigForm(forms.SelfHandlingForm): + failure_url = 'horizon:dc_admin:dc_software_management:index' + + APPLY_TYPES = ( + ('parallel', _("Parallel")), + ('serial', _("Serial")), + ) + + INSTANCE_ACTIONS = ( + ('migrate', _("Migrate")), + ('stop-start', _("Stop-Start")), + ) + + ALARM_RESTRICTION_TYPES = ( + ('relaxed', _("Relaxed")), + ('strict', _("Strict")), + ) + + subcloud = forms.ChoiceField( + label=_("Subcloud"), + required=True, + widget=forms.Select()) + + storage_apply_type = forms.ChoiceField( + label=_("Storage Apply Type"), + required=True, + choices=APPLY_TYPES, + widget=forms.Select()) + + compute_apply_type = forms.ChoiceField( + label=_("Compute Apply Type"), + required=True, + choices=APPLY_TYPES, + widget=forms.Select( + attrs={ + 'class': 'switchable', + 'data-slug': 'compute_apply_type'})) + + max_parallel_computes = forms.IntegerField( + label=_("Maximum Parallel Compute Hosts"), + initial=2, + min_value=2, + max_value=100, + required=True, + error_messages={'invalid': _('Maximum Parallel Compute Hosts must be ' + 'between 2 and 100.')}, + widget=forms.TextInput( + attrs={ + 'class': 'switched', + 'data-switch-on': 'compute_apply_type', + 'data-compute_apply_type-parallel': + 'Maximum Parallel Compute Hosts'})) + + default_instance_action = forms.ChoiceField( + label=_("Default Instance Action"), + required=True, + choices=INSTANCE_ACTIONS, + widget=forms.Select()) + + alarm_restriction_type = forms.ChoiceField( + label=_("Alarm Restrictions"), + required=True, + choices=ALARM_RESTRICTION_TYPES, + widget=forms.Select()) + + def __init__(self, request, *args, **kwargs): + super(CreateCloudPatchConfigForm, self).__init__(request, *args, + **kwargs) + subcloud_list = [(api.dc_manager.DEFAULT_CONFIG_NAME, + api.dc_manager.DEFAULT_CONFIG_NAME), ] + subclouds = api.dc_manager.subcloud_list(self.request) + subcloud_list.extend([(c.name, c.name) for c in subclouds]) + self.fields['subcloud'].choices = subcloud_list + + if self.initial.get('subcloud', None): + self.fields['subcloud'].widget.attrs['disabled'] = 'disabled' + + def handle(self, request, data): + try: + for k in data.keys(): + if '_' in k: + data[k.replace('_', '-')] = data[k] + del data[k] + + subcloud = data['subcloud'] + if subcloud == api.dc_manager.DEFAULT_CONFIG_NAME: + subcloud = None + del data['subcloud'] + + response = api.dc_manager.config_update(request, subcloud, data) + if not response: + messages.error(request, "Cloud Patching Configuration " + "creation failed") + + except exc.APIException as e: + LOG.error(e.error_message) + messages.error(request, e.error_message) + + redirect = reverse(self.failure_url) + exceptions.handle(request, e.error_message, redirect=redirect) + except Exception: + redirect = reverse(self.failure_url) + exceptions.handle(request, + "Cloud Patching Configuration creation failed", + redirect=redirect) + return True diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/panel.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/panel.py new file mode 100755 index 00000000..8bfb6c87 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/panel.py @@ -0,0 +1,30 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from django.utils.translation import ugettext_lazy as _ + +import horizon +from starlingx_dashboard.dashboards.dc_admin import dashboard + + +class DCSoftwareManagement(horizon.Panel): + name = _("Software Management") + slug = 'dc_software_management' + + def allowed(self, context): + if context['request'].user.services_region != 'SystemController': + return False + + return super(DCSoftwareManagement, self).allowed(context) + + def nav(self, context): + if context['request'].user.services_region != 'SystemController': + return False + + return super(DCSoftwareManagement, self).allowed(context) + + +dashboard.DCAdmin.register(DCSoftwareManagement) diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tables.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tables.py new file mode 100755 index 00000000..20ebd9da --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tables.py @@ -0,0 +1,327 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import logging + +from django.core.urlresolvers import reverse # noqa +from django.template.defaultfilters import safe, title # noqa +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ungettext_lazy + +from horizon import exceptions +from horizon import messages +from horizon import tables + +from starlingx_dashboard import api +from starlingx_dashboard.dashboards.admin.software_management import tables \ + as AdminTables + +LOG = logging.getLogger(__name__) + + +# Patching +class UploadPatch(AdminTables.UploadPatch): + url = "horizon:dc_admin:dc_software_management:dc_patchupload" + + +class PatchesTable(AdminTables.PatchesTable): + patch_id = tables.Column('patch_id', + link="horizon:dc_admin:dc_software_management:" + "dc_patchdetail", + verbose_name=_('Patch ID')) + + class Meta(object): + name = "dc_patches" + multi_select = True + row_class = AdminTables.UpdatePatchRow + status_columns = ['patchstate'] + row_actions = (AdminTables.ApplyPatch, AdminTables.RemovePatch, + AdminTables.DeletePatch) + table_actions = ( + AdminTables.PatchFilterAction, UploadPatch, AdminTables.ApplyPatch, + AdminTables.RemovePatch, AdminTables.DeletePatch) + verbose_name = _("Patches") + hidden_title = False + + +# Cloud Patch Orchestration +def get_cached_cloud_strategy(request, table): + if 'cloudpatchstrategy' not in table.kwargs: + table.kwargs['cloudpatchstrategy'] = \ + api.dc_manager.get_strategy(request) + return table.kwargs['cloudpatchstrategy'] + + +class CreateCloudPatchStrategy(tables.LinkAction): + name = "createcloudpatchstrategy" + url = "horizon:dc_admin:dc_software_management:createcloudpatchstrategy" + verbose_name = _("Create Strategy") + classes = ("ajax-modal", "btn-create") + icon = "plus" + + def allowed(self, request, datum): + try: + strategy = get_cached_cloud_strategy(request, self.table) + + classes = [c for c in self.classes if c != "disabled"] + self.classes = classes + if strategy: + if "disabled" not in self.classes: + self.classes = [c for c in self.classes] + ['disabled'] + except Exception as ex: + LOG.exception(ex) + return True + + +class DeleteCloudPatchStrategy(tables.Action): + name = "delete_patch_strategy" + force = False + disabled = False + requires_input = False + icon = 'trash' + action_type = 'danger' + verbose_name = _("Delete Strategy") + confirm_message = "You have selected Delete Strategy. " \ + "Please confirm your selection" + + def allowed(self, request, datum): + try: + strategy = get_cached_cloud_strategy(request, self.table) + self.disabled = True + if strategy and strategy.state in ['initial', 'complete', 'failed', + 'aborted']: + self.disabled = False + except Exception as ex: + LOG.exception(ex) + return True + + def get_default_classes(self): + try: + if self.disabled: + return ['disabled'] + return super(DeleteCloudPatchStrategy, self).get_default_classes() + except Exception as ex: + LOG.exception(ex) + + def single(self, table, request, obj_id): + try: + result = api.dc_manager.strategy_delete(request) + if result: + messages.success(request, "Strategy Deleted") + else: + messages.error(request, "Strategy delete failed") + except Exception as ex: + LOG.exception(ex) + messages.error(request, ex.message) + + +class ApplyCloudPatchStrategy(tables.Action): + name = "apply_cloud_patch_strategy" + requires_input = False + disabled = False + verbose_name = _("Apply Strategy") + + def allowed(self, request, datum): + try: + strategy = get_cached_cloud_strategy(request, self.table) + self.disabled = False + if not strategy or strategy.state != 'initial': + self.disabled = True + except Exception as ex: + LOG.exception(ex) + return True + + def get_default_classes(self): + try: + if self.disabled: + return ['disabled'] + return super(ApplyCloudPatchStrategy, self).get_default_classes() + except Exception as ex: + LOG.exception(ex) + + def single(self, table, request, obj_id): + try: + result = api.dc_manager.strategy_apply(request) + if result: + messages.success(request, "Strategy apply in progress") + else: + messages.error(request, "Strategy apply failed") + except Exception as ex: + LOG.exception(ex) + messages.error(request, ex.message) + + +class AbortCloudPatchStrategy(tables.Action): + name = "abort_cloud_patch_strategy" + requires_input = False + disabled = False + action_type = 'danger' + verbose_name = _("Abort Strategy") + confirm_message = "You have selected Abort Strategy. " \ + "Please confirm your selection" + + def allowed(self, request, datum): + try: + strategy = get_cached_cloud_strategy(request, self.table) + self.disabled = False + if not strategy or strategy.state != 'applying': + self.disabled = True + except Exception as ex: + LOG.exception(ex) + return True + + def get_default_classes(self): + try: + if self.disabled: + return ['disabled'] + return super(AbortCloudPatchStrategy, self).get_default_classes() + except Exception as ex: + LOG.exception(ex) + + def single(self, table, request, obj_id): + try: + result = api.dc_manager.strategy_abort(request) + if result: + messages.success(request, "Strategy abort in progress") + else: + messages.error(request, "Strategy abort failed") + except Exception as ex: + LOG.exception(ex) + messages.error(request, ex.message) + + +STEP_STATE_CHOICES = ( + (None, True), + ("", True), + ("none", True), + ("complete", True), + ("initial", True), + ("failed", False), + ("timed-out", False), + ("aborted", False), +) + + +def get_apply_percent(cell): + if '(' in cell and '%)' in cell: + percent = cell.split('(')[1].split('%)')[0] + return {'percent': "%d%%" % float(percent)} + return {} + + +def get_state(step): + state = step.state + if '%' in step.details: + percent = [s for s in step.details.split(' ') if '%' in s] + if percent and len(percent): + percent = percent[0] + state += " (%s)" % percent + return state + + +class CloudPatchStepsTable(tables.DataTable): + cloud = tables.Column('cloud', verbose_name=_('Cloud')) + stage = tables.Column('stage', verbose_name=_('Stage')) + state = tables.Column(get_state, + verbose_name=_('State'), + status=True, + status_choices=STEP_STATE_CHOICES, + filters=(safe,), + cell_attributes_getter=get_apply_percent) + details = tables.Column('details', + verbose_name=_("Details"),) + started_at = tables.Column('started_at', + verbose_name=_('Started At')) + finished_at = tables.Column('finished_at', + verbose_name=_('Finished At')) + + def get_object_id(self, obj): + return "%s" % obj.cloud + + class Meta(object): + name = "cloudpatchsteps" + multi_select = False + status_columns = ['state', ] + table_actions = (CreateCloudPatchStrategy, ApplyCloudPatchStrategy, + AbortCloudPatchStrategy, DeleteCloudPatchStrategy) + verbose_name = _("Steps") + hidden_title = False + + +# Cloud Patch Config +class CreateCloudPatchConfig(tables.LinkAction): + name = "createcloudpatchconfig" + url = "horizon:dc_admin:dc_software_management:createcloudpatchconfig" + verbose_name = _("Create New Cloud Patching Configuration") + classes = ("ajax-modal", "btn-create") + icon = "plus" + + +class EditCloudPatchConfig(tables.LinkAction): + name = "editcloudpatchconfig" + url = "horizon:dc_admin:dc_software_management:editcloudpatchconfig" + verbose_name = _("Edit Configuration") + classes = ("ajax-modal",) + + +class DeleteCloudPatchConfig(tables.DeleteAction): + @staticmethod + def action_present(count): + return ungettext_lazy( + u"Delete Cloud Patching Configuration", + u"Delete Cloud Patching Configurations", + count + ) + + @staticmethod + def action_past(count): + return ungettext_lazy( + u"Deleted Cloud Patching Configuration", + u"Deleted Cloud Patching Configurations", + count + ) + + def allowed(self, request, config=None): + if config and config.cloud == api.dc_manager.DEFAULT_CONFIG_NAME: + return False + return True + + def delete(self, request, config): + try: + api.dc_manager.config_delete(request, config) + except Exception: + msg = _('Failed to delete configuration for subcloud %(cloud)') % \ + {'cloud': config, } + redirect = reverse('horizon:dc_admin:dc_software_management:index') + exceptions.handle(request, msg, redirect=redirect) + + +class CloudPatchConfigTable(tables.DataTable): + cloud = tables.Column('cloud', verbose_name=_('Cloud')) + storage_apply_type = tables.Column('storage_apply_type', + verbose_name=_('Storage Apply Type')) + compute_apply_type = tables.Column('compute_apply_type', + verbose_name=_('Compute Apply Type')) + max_parallel_computes = tables.Column( + 'max_parallel_computes', verbose_name=_('Max Parallel Computes')) + default_instance_action = tables.Column( + 'default_instance_action', verbose_name=_('Default Instance Action')) + alarm_restriction_type = tables.Column( + 'alarm_restriction_type', verbose_name=_('Alarm Restrictions')) + + def get_object_id(self, obj): + return "%s" % obj.cloud + + def get_object_display(self, obj): + return obj.cloud + + class Meta(object): + name = "cloudpatchconfig" + multi_select = False + table_actions = (CreateCloudPatchConfig,) + row_actions = (EditCloudPatchConfig, DeleteCloudPatchConfig,) + verbose_name = _("Cloud Patching Configurations") + hidden_title = False diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tabs.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tabs.py new file mode 100755 index 00000000..94a89d5e --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/tabs.py @@ -0,0 +1,93 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import logging + +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import tabs +from starlingx_dashboard import api +from starlingx_dashboard.dashboards.dc_admin.dc_software_management \ + import tables as tables + +LOG = logging.getLogger(__name__) + + +class PatchesTab(tabs.TableTab): + table_classes = (tables.PatchesTable,) + name = _("Patches") + slug = "patches" + template_name = ("dc_admin/dc_software_management/_patches.html") + + def get_dc_patches_data(self): + request = self.request + patches = [] + try: + patches = api.patch.get_patches(request) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve patch list.')) + + return patches + + +class CloudPatchOrchestrationTab(tabs.TableTab): + table_classes = (tables.CloudPatchStepsTable,) + name = _("Cloud Patching Orchestration") + slug = "cloud_patch_orchestration" + template_name = ("dc_admin/dc_software_management/" + "_cloud_patch_orchestration.html") + + def get_context_data(self, request): + context = super(CloudPatchOrchestrationTab, self).\ + get_context_data(request) + + strategy = None + try: + strategy = api.dc_manager.get_strategy(request) + except Exception as ex: + LOG.exception(ex) + exceptions.handle(request, + _('Unable to retrieve current strategy.')) + context['strategy'] = strategy + return context + + def get_cloudpatchsteps_data(self): + request = self.request + steps = [] + try: + steps = api.dc_manager.step_list(request) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve steps list.')) + + return steps + + +class CloudPatchConfigTab(tabs.TableTab): + table_classes = (tables.CloudPatchConfigTable,) + name = _("Cloud Patching Configuration") + slug = "cloud_patch_config" + template_name = ("dc_admin/dc_software_management/" + "_cloud_patch_config.html") + + def get_cloudpatchconfig_data(self): + request = self.request + steps = [] + try: + steps = api.dc_manager.config_list(request) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve configuration list.')) + + return steps + + +class DCSoftwareManagementTabs(tabs.TabGroup): + slug = "dc_software_management_tabs" + tabs = (PatchesTab, CloudPatchOrchestrationTab, CloudPatchConfigTab) + sticky = True diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_config.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_config.html new file mode 100755 index 00000000..3152a514 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_config.html @@ -0,0 +1,5 @@ +{% load i18n sizeformat %} + +{% block main %} + {{ cloudpatchconfig_table.render }} +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_orchestration.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_orchestration.html new file mode 100755 index 00000000..ec70f6fc --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_cloud_patch_orchestration.html @@ -0,0 +1,29 @@ +{% load i18n sizeformat %} + +{% block main %} + +
+

{% trans "Cloud Patch Strategy" %}

+
+
+ + {% if strategy %} +
+
{% trans "Subcloud Apply Type" %}
+
{{ strategy.subcloud_apply_type }}
+
{% trans "Max Parallel Subclouds" %}
+
{{ strategy.max_parallel_subclouds }}
+
{% trans "Stop On Failure" %}
+
{{ strategy.stop_on_failure }}
+
{% trans "State" %}
+
{{ strategy.state }}
+
+ {% else %} + {% trans "No Strategy has been created" %} + {% endif %} +
+
+
+ {{ cloudpatchsteps_table.render }} + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_config.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_config.html new file mode 100755 index 00000000..7f84db2f --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_config.html @@ -0,0 +1,28 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_action %}{% url 'horizon:dc_admin:dc_software_management:createcloudpatchconfig' %}{% endblock %} + +{% block modal-header %}{% trans "Create New Cloud Patching Configuration" %}{% endblock %} + +{% block modal-body %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% trans "Description:" %}

+

+ {% trans "Create a configuration for a specific subcloud to use the specified patch strategy settings instead of the defaults values." %} +

+

+ {% trans "Note: for Simplex systems, the default instance action must be set to stop-start (since migration is not possible on a single-node system)." %} +

+
+{% endblock %} + +{% block modal-footer %} + Cancel + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_strategy.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_strategy.html new file mode 100755 index 00000000..921a18d4 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_create_cloud_patch_strategy.html @@ -0,0 +1,25 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_action %}{% url 'horizon:dc_admin:dc_software_management:createcloudpatchstrategy' %}{% endblock %} + +{% block modal-header %}{% trans "Create Patch Strategy" %}{% endblock %} + +{% block modal-body %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% trans "Description:" %}

+

+ {% trans "Create a strategy to specify how the clouds should be patched." %} +

+
+{% endblock %} + +{% block modal-footer %} + Cancel + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_detail_patches.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_detail_patches.html new file mode 100755 index 00000000..c3797ae7 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_detail_patches.html @@ -0,0 +1,54 @@ +{% extends 'base.html' %} +{% load i18n breadcrumb_nav %} +{% block title %}{% trans "Patch Details" %}{% endblock %} + +{% block main %} +

{{patch.patch_id }}

+ +
+
+
+

{% trans "Info" %}

+
+
+
{% trans "Patch State" %}
+
{{ patch.patchstate }}
+
{% trans "Platform Release Version" %}
+
{{ patch.sw_version }}
+
{% trans "Reboot-Required" %}
+
{{ patch.reboot_required }}
+
{% trans "Patch Status Code" %}
+
{{ patch.status }}
+ {% if patch.unremovable == "Y" %} +
{% trans "Unremovable" %}
+
{% trans "This patch cannot be removed" %}
+ {% endif %} +
{% trans "Required Patches" %}
+
{{ patch.requires_display|linebreaks }}
+
+
+
{% trans "Summary" %}
+
{{ patch.summary|linebreaks }}
+
+
+
{% trans "Description" %}
+
{{ patch.description|linebreaks }}
+
+
+
{% trans "Warnings" %}
+
{{ patch.warnings|linebreaks }}
+
+
+
{% trans "Installation Instructions" %}
+
{{ patch.install_instructions|linebreaks }}
+
+
+
{% trans "Contents" %}
+
{{ patch.contents_display|linebreaks }}
+
+
+
+
+{% endblock %} + + diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_edit_cloud_patch_config.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_edit_cloud_patch_config.html new file mode 100755 index 00000000..4a7df733 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_edit_cloud_patch_config.html @@ -0,0 +1,28 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_action %}{% url 'horizon:dc_admin:dc_software_management:editcloudpatchconfig' subcloud %}{% endblock %} + +{% block modal-header %}{% trans "Edit Cloud Patch Configuration" %}{% endblock %} + +{% block modal-body %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% trans "Description:" %}

+

+ {% trans "Edit a configuration for a specific subcloud to use the specified patch strategy settings instead of the defaults values." %} +

+

+ {% trans "Note: for Simplex systems, the default instance action must be set to stop-start (since migration is not possible on a single-node system)." %} +

+
+{% endblock %} + +{% block modal-footer %} + Cancel + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_patches.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_patches.html new file mode 100755 index 00000000..e5ce3bba --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_patches.html @@ -0,0 +1,10 @@ +{% load i18n sizeformat %} + +{% block main %} +
+ {{ dc_patches_table.render }} +
+{% endblock %} + + + diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_upload_patch.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_upload_patch.html new file mode 100755 index 00000000..5420df0c --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/_upload_patch.html @@ -0,0 +1,27 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_action %}{% url 'horizon:dc_admin:dc_software_management:dc_patchupload' %}{% endblock %} +{% block form_attrs %}enctype="multipart/form-data"{% endblock %} + +{% block modal-header %}{% trans "Upload Patches" %}{% endblock %} + +{% block modal-body %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% trans "Description:" %}

+

+ {% trans "Specify one or more patch files to upload to the Patching Service." %} +

+ +
+{% endblock %} + +{% block modal-footer %} + Cancel + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_config.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_config.html new file mode 100755 index 00000000..b9f46f1f --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_config.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Create New Cloud Patching Configuration" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Create New Cloud Patching Configuration") %} +{% endblock page_header %} + +{% block main %} + {% include 'dc_admin/dc_software_management/_create_cloud_patch_config.html' %} +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_strategy.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_strategy.html new file mode 100755 index 00000000..adccc330 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/create_cloud_patch_strategy.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Create Patch Strategy" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Create Patch Strategy") %} +{% endblock page_header %} + +{% block main %} + {% include 'dc_admin/dc_software_management/_create_cloud_patch_strategy.html' %} +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/edit_cloud_patch_config.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/edit_cloud_patch_config.html new file mode 100755 index 00000000..71904b55 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/edit_cloud_patch_config.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Edit Cloud Patching Configuration" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Edit Cloud Patching Configuration") %} +{% endblock page_header %} + +{% block main %} + {% include 'dc_admin/dc_software_management/_edit_cloud_patch_config.html' %} +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/index.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/index.html new file mode 100755 index 00000000..6cf88059 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/index.html @@ -0,0 +1,28 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Software Management" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Software Management") %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} + +{% block js %} + {{ block.super }} + +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/upload_patch.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/upload_patch.html new file mode 100755 index 00000000..ae74025d --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/templates/dc_software_management/upload_patch.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Upload Patches" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Upload Patches") %} +{% endblock page_header %} + +{% block main %} + {% include 'dc_admin/dc_software_management/_upload_patch.html' %} +{% endblock %} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/urls.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/urls.py new file mode 100755 index 00000000..fe6eaf56 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/urls.py @@ -0,0 +1,35 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from django.conf.urls import url + +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import CreateCloudPatchConfigView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import CreateCloudPatchStrategyView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import DetailPatchView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import EditCloudPatchConfigView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import IndexView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.views \ + import UploadPatchView + +urlpatterns = [ + url(r'^$', IndexView.as_view(), name='index'), + url(r'^(?P[^/]+)/patchdetail/$', + DetailPatchView.as_view(), name='dc_patchdetail'), + url(r'^dc_patchupload/$', UploadPatchView.as_view(), + name='dc_patchupload'), + url(r'^createcloudpatchstrategy/$', CreateCloudPatchStrategyView.as_view(), + name='createcloudpatchstrategy'), + url(r'^createcloudpatchconfig/$', CreateCloudPatchConfigView.as_view(), + name='createcloudpatchconfig'), + url(r'^(?P[^/]+)/editcloudpatchconfig/$', + EditCloudPatchConfigView.as_view(), + name='editcloudpatchconfig'), +] diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/views.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/views.py new file mode 100755 index 00000000..0455e942 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_software_management/views.py @@ -0,0 +1,94 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import logging + +from django.core.urlresolvers import reverse_lazy +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import tabs + +from starlingx_dashboard import api +from starlingx_dashboard.dashboards.admin.software_management.views import \ + DetailPatchView as AdminDetailPatchView +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.forms \ + import CreateCloudPatchConfigForm +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.forms \ + import CreateCloudPatchStrategyForm +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.forms \ + import UploadPatchForm +from starlingx_dashboard.dashboards.dc_admin.dc_software_management.tabs \ + import DCSoftwareManagementTabs + +LOG = logging.getLogger(__name__) + + +class IndexView(tabs.TabbedTableView): + tab_group_class = DCSoftwareManagementTabs + template_name = 'dc_admin/dc_software_management/index.html' + page_title = _("Software Management") + + def get_tabs(self, request, *args, **kwargs): + return self.tab_group_class(request, **kwargs) + + +class UploadPatchView(forms.ModalFormView): + form_class = UploadPatchForm + template_name = 'dc_admin/dc_software_management/upload_patch.html' + context_object_name = 'patch' + success_url = reverse_lazy("horizon:dc_admin:dc_software_management:index") + + +class DetailPatchView(AdminDetailPatchView): + template_name = 'dc_admin/dc_software_management/_detail_patches.html' + failure_url = 'horizon:dc_admin:dc_software_management:index' + + +class CreateCloudPatchStrategyView(forms.ModalFormView): + form_class = CreateCloudPatchStrategyForm + template_name = 'dc_admin/dc_software_management/' \ + 'create_cloud_patch_strategy.html' + context_object_name = 'strategy' + success_url = reverse_lazy("horizon:dc_admin:dc_software_management:index") + + +class CreateCloudPatchConfigView(forms.ModalFormView): + form_class = CreateCloudPatchConfigForm + template_name = 'dc_admin/dc_software_management/' \ + 'create_cloud_patch_config.html' + context_object_name = 'config' + success_url = reverse_lazy("horizon:dc_admin:dc_software_management:index") + + +class EditCloudPatchConfigView(forms.ModalFormView): + form_class = CreateCloudPatchConfigForm + template_name = 'dc_admin/dc_software_management/' \ + 'edit_cloud_patch_config.html' + context_object_name = 'config' + success_url = reverse_lazy("horizon:dc_admin:dc_software_management:index") + + def get_context_data(self, **kwargs): + context = super(EditCloudPatchConfigView, self).get_context_data( + **kwargs) + context['subcloud'] = self.kwargs['subcloud'] + return context + + def get_initial(self): + try: + config = api.dc_manager.config_get(self.request, + self.kwargs['subcloud']) + except Exception: + exceptions.handle(self.request, _("Unable to retrieve subcloud " + "configuration data.")) + + return {'subcloud': config.cloud, + 'storage_apply_type': config.storage_apply_type, + 'compute_apply_type': config.compute_apply_type, + 'max_parallel_computes': config.max_parallel_computes, + 'default_instance_action': config.default_instance_action, + 'alarm_restriction_type': config.alarm_restriction_type} diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2210_starlingx_dc_admin_cloud_overview_panel.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2211_starlingx_dc_admin_cloud_overview_panel.py similarity index 100% rename from starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2210_starlingx_dc_admin_cloud_overview_panel.py rename to starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2211_starlingx_dc_admin_cloud_overview_panel.py diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2212_WRS_dc_admin_software_management_panel.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2212_WRS_dc_admin_software_management_panel.py new file mode 100644 index 00000000..863b8674 --- /dev/null +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/enabled/_2212_WRS_dc_admin_software_management_panel.py @@ -0,0 +1,10 @@ +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'dc_software_management' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'dc_admin' +# The slug of the panel group the PANEL is associated with. +PANEL_GROUP = 'default' + +# Python panel class of the PANEL to be added. +ADD_PANEL = 'starlingx_dashboard.dashboards.' \ + 'dc_admin.dc_software_management.panel.DCSoftwareManagement' diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/exceptions.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/exceptions.py index 8738a775..a8543ecb 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/exceptions.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/exceptions.py @@ -12,6 +12,7 @@ # under the License. from cgtsclient import exc as cgtsclient +from dcmanagerclient import exceptions as dcmanagerclient UNAUTHORIZED = ( @@ -28,4 +29,5 @@ RECOVERABLE = ( cgtsclient.HTTPBadRequest, cgtsclient.HTTPConflict, cgtsclient.CommunicationError, + dcmanagerclient.APIException )