From 3c9dcb8e4d83085fb216cabf3d086c604d481e25 Mon Sep 17 00:00:00 2001 From: xiangxinyong Date: Tue, 19 Apr 2016 19:50:27 +0800 Subject: [PATCH] [Operation Logs] Submit index view function Change-Id: I2c97d4854d7cd39f039e51146f7582abfd3bd531 Closes-Bug: #1571462 --- smaug_dashboard/operationlogs/tables.py | 77 ++++++++++ smaug_dashboard/operationlogs/utils.py | 39 +++++ smaug_dashboard/operationlogs/views.py | 143 +++++++++++++++++- .../templates/operationlogs/_index.html | 25 +++ .../templates/operationlogs/index.html | 7 +- 5 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 smaug_dashboard/operationlogs/tables.py create mode 100644 smaug_dashboard/operationlogs/utils.py create mode 100644 smaug_dashboard/templates/operationlogs/_index.html diff --git a/smaug_dashboard/operationlogs/tables.py b/smaug_dashboard/operationlogs/tables.py new file mode 100644 index 0000000..d7cac52 --- /dev/null +++ b/smaug_dashboard/operationlogs/tables.py @@ -0,0 +1,77 @@ +# Copyright (c) 2016 Huawei, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.utils.translation import ugettext_lazy as _ + +from horizon import tables + + +class OperationLogsProtectTable(tables.DataTable): + id = tables.Column('id', + link="horizon:smaug:operationlogs:detail", + verbose_name=_('ID')) + name = tables.Column('name', + verbose_name=_('Name')) + type = tables.Column('type', + verbose_name=_('Type')) + status = tables.Column('status', + verbose_name=_('Status')) + + class Meta(object): + name = 'operationlogs' + verbose_name = _('Operation Logs') + + +class OperationLogsRestoreTable(tables.DataTable): + id = tables.Column( + 'id', + verbose_name=_('ID')) + name = tables.Column( + 'name', + verbose_name=_('Protection Plan')) + type = tables.Column( + 'type', + verbose_name=_('Type')) + status = tables.Column( + 'status', + verbose_name=_('Status')) + restore_from_checkpoint = tables.Column( + 'checkpoint_id', + verbose_name=_('Restore From Checkpoint')) + restore_target = tables.Column( + 'restore_target', + verbose_name=_('Restore Target')) + protection_provider = tables.Column( + 'provider_name', + verbose_name=_('Protection Provider')) + + class Meta(object): + name = 'operationlogs' + verbose_name = _('Operation Logs') + + +class OperationLogsDeleteTable(tables.DataTable): + id = tables.Column('id', + link="horizon:smaug:operationlogs:detail", + verbose_name=_('ID')) + name = tables.Column('name', + verbose_name=_('Name')) + type = tables.Column('type', + verbose_name=_('Type')) + status = tables.Column('status', + verbose_name=_('Status')) + + class Meta(object): + name = 'operationlogs' + verbose_name = _('Operation Logs') diff --git a/smaug_dashboard/operationlogs/utils.py b/smaug_dashboard/operationlogs/utils.py new file mode 100644 index 0000000..8e1150b --- /dev/null +++ b/smaug_dashboard/operationlogs/utils.py @@ -0,0 +1,39 @@ +# Copyright (c) 2016 Huawei, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import collections +from django.utils.translation import ugettext_lazy as _ + +OPERATION_TYPE_FILTER = 'type_filter' +OPERATION_STATUS_FILTER = 'status_filter' + +OPERATION_TYPE_PROTECT = 'Protect' +OPERATION_TYPE_RESTORE = 'Restore' +OPERATION_TYPE_DELETE = 'Delete' + +OPERATION_TYPE_CHOICES = [(OPERATION_TYPE_PROTECT, _('Protect')), + (OPERATION_TYPE_RESTORE, _('Restore')), + (OPERATION_TYPE_DELETE, _('Delete'))] +OPERATION_TYPE_DICT = collections.OrderedDict(OPERATION_TYPE_CHOICES) + +OPERATION_STATUS_COMMITED = 'commited' +OPERATION_STATUS_RUNNING = 'running' +OPERATION_STATUS_FINISHED = 'finished' +OPERATION_STATUS_FAILED = 'failed' + +OPERATION_STATUS_CHOICES = [(OPERATION_STATUS_COMMITED, _('Commited')), + (OPERATION_STATUS_RUNNING, _('Running')), + (OPERATION_STATUS_FINISHED, _('Finished')), + (OPERATION_STATUS_FAILED, _('Failed'))] +OPERATION_STATUS_DICT = collections.OrderedDict(OPERATION_STATUS_CHOICES) diff --git a/smaug_dashboard/operationlogs/views.py b/smaug_dashboard/operationlogs/views.py index 556437d..4942923 100644 --- a/smaug_dashboard/operationlogs/views.py +++ b/smaug_dashboard/operationlogs/views.py @@ -12,9 +12,146 @@ # License for the specific language governing permissions and limitations # under the License. -from horizon import views +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import tables as horizon_tables + +from smaug_dashboard.api import smaug as smaugclient +from smaug_dashboard.operationlogs import tables +from smaug_dashboard.operationlogs import utils -class IndexView(views.APIView): - # A very simple class-based view... +class IndexView(horizon_tables.DataTableView): + table_class = tables.OperationLogsProtectTable template_name = 'operationlogs/index.html' + page_title = _("Operation Logs") + + def get_table(self): + if not self.table_class: + raise AttributeError('You must specify a DataTable class for the ' + '"table_class" attribute on %s.' + % self.__class__.__name__) + # Protect is the default operation type + type_filter = self.request.POST.get(utils.OPERATION_TYPE_FILTER, + utils.OPERATION_TYPE_PROTECT) + self.table_class = eval("tables.OperationLogs%sTable" + % str(type_filter)) + if not hasattr(self, "table"): + self.table = self.table_class(self.request, **self.kwargs) + return self.table + + def get_filter_list(self): + filters = {} + + # Operation type + filters[utils.OPERATION_TYPE_FILTER] = \ + self.request.POST.get(utils.OPERATION_TYPE_FILTER, + utils.OPERATION_TYPE_PROTECT) + # Operation status + filters[utils.OPERATION_STATUS_FILTER] = \ + self.request.POST.get(utils.OPERATION_STATUS_FILTER, u"All") + + return filters + + def get_context_data(self, **kwargs): + context = super(IndexView, self).get_context_data(**kwargs) + context["type_list"] = utils.OPERATION_TYPE_CHOICES + context["status_list"] = utils.OPERATION_STATUS_CHOICES + context["url"] = reverse("horizon:smaug:operationlogs:index") + context = dict(context, **self.get_filter_list()) + return context + + def get_search_opts(self): + search_opts = self.get_filter_list() + for key, val in search_opts.items(): + if val == u"All": + search_opts.pop(key) + return search_opts + + def has_prev_data(self, table): + return self._prev + + def has_more_data(self, table): + return self._more + + def get_data(self): + logs = [] + try: + search_opts = self.get_search_opts() + search_type = search_opts.get(utils.OPERATION_TYPE_FILTER, + utils.OPERATION_TYPE_PROTECT) + + if search_type == utils.OPERATION_TYPE_PROTECT: + logs = self.get_protect_data(search_opts) + elif search_type == utils.OPERATION_TYPE_RESTORE: + logs = self.get_restore_data(search_opts) + elif search_type == utils.OPERATION_TYPE_DELETE: + logs = self.get_delete_data(search_opts) + + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve operation log list.')) + return logs + + def get_protect_data(self, search_opts): + # TODO(xiangxinyong) Get protect operation logs + logs, self._more, self._prev = ([], False, False) + return logs + + def get_restore_data(self, search_opts): + prev_marker = self.request.GET.get( + tables.OperationLogsRestoreTable._meta.prev_pagination_param, + None) + + if prev_marker is not None: + marker = prev_marker + else: + marker = self.request.GET.get( + tables.OperationLogsRestoreTable._meta.pagination_param, + None) + + reversed_order = prev_marker is not None + logs = [] + try: + # Get filter_opts + filter_opts = None + status = search_opts.get(utils.OPERATION_STATUS_FILTER, None) + if status is not None: + filter_opts = {"status": status} + + # Get restore operation logs + logs, self._more, self._prev = \ + smaugclient.restore_list_paged( + self.request, + search_opts=filter_opts, + marker=marker, + paginate=True, + sort_dir='asc', + sort_key='id', + reversed_order=reversed_order) + + for log in logs: + checkpoint = smaugclient.checkpoint_get(self.request, + log.provider_id, + log.checkpoint_id) + provider = smaugclient.provider_get(self.request, + log.provider_id) + setattr(log, "name", checkpoint.protection_plan["name"]) + setattr(log, "type", + utils.OPERATION_TYPE_DICT[ + utils.OPERATION_TYPE_RESTORE]) + setattr(log, "provider_name", provider.name) + + except Exception: + self._prev = False + self._more = False + exceptions.handle(self.request, + _('Unable to retrieve restore list.')) + return logs + + def get_delete_data(self, search_opts): + # TODO(xiangxinyong) Get delete operation logs + logs, self._more, self._prev = ([], False, False) + return logs diff --git a/smaug_dashboard/templates/operationlogs/_index.html b/smaug_dashboard/templates/operationlogs/_index.html new file mode 100644 index 0000000..8655c1a --- /dev/null +++ b/smaug_dashboard/templates/operationlogs/_index.html @@ -0,0 +1,25 @@ +{% load i18n %} + +
+{% csrf_token %} + +
+ +
+ +
diff --git a/smaug_dashboard/templates/operationlogs/index.html b/smaug_dashboard/templates/operationlogs/index.html index 14fd3aa..21d2df0 100644 --- a/smaug_dashboard/templates/operationlogs/index.html +++ b/smaug_dashboard/templates/operationlogs/index.html @@ -5,10 +5,7 @@ {% trans "Operation Logs" %} {% endblock %} -{% block page_header %} - -{% endblock page_header %} - {% block main %} -
+ {% include "operationlogs/_index.html" %} + {{ table.render }} {% endblock %}