diff --git a/manila_ui/api/manila.py b/manila_ui/api/manila.py index af693d60..8350f784 100644 --- a/manila_ui/api/manila.py +++ b/manila_ui/api/manila.py @@ -175,6 +175,17 @@ def share_extend(request, share_id, new_size): return manilaclient(request).shares.extend(share_id, new_size) +def share_revert(request, share, snapshot): + """Sends request to revert share to specific snapshot. + + This API available only since 2.27 microversion. + + :param share: Share class instance or share ID + :param snapshot: ShareSnapshot class instance or share snapshot ID + """ + return manilaclient(request).shares.revert_to_snapshot(share, snapshot) + + def share_snapshot_get(request, snapshot_id): return manilaclient(request).share_snapshots.get(snapshot_id) diff --git a/manila_ui/dashboards/project/shares/shares/forms.py b/manila_ui/dashboards/project/shares/shares/forms.py index cf8b847e..cebcaab4 100644 --- a/manila_ui/dashboards/project/shares/shares/forms.py +++ b/manila_ui/dashboards/project/shares/shares/forms.py @@ -405,3 +405,48 @@ class ExtendForm(forms.SelfHandlingForm): exceptions.handle(request, _('Unable to extend share.'), redirect=redirect) + + +class RevertForm(forms.SelfHandlingForm): + """Form for reverting a share to a snapshot.""" + + snapshot = forms.ChoiceField( + label=_("Snapshot"), + required=True, + widget=forms.Select( + attrs={'class': 'switchable', 'data-slug': 'share_snapshot'})) + + def __init__(self, req, *args, **kwargs): + super(self.__class__, self).__init__(req, *args, **kwargs) + # NOTE(vponomaryov): manila client does not allow to filter snapshots + # using "created_at" field, so, we need to get all snapshots of a share + # and do filtering here. + search_opts = {'share_id': self.initial['share_id']} + snapshots = manila.share_snapshot_list(req, search_opts=search_opts) + amount_of_snapshots = len(snapshots) + if amount_of_snapshots < 1: + self.fields['snapshot'].choices = [("", "")] + else: + snapshot = snapshots[0] + if amount_of_snapshots > 1: + for s in snapshots[1:]: + if s.created_at > snapshot.created_at: + snapshot = s + self.fields['snapshot'].choices = [ + (snapshot.id, snapshot.name or snapshot.id)] + + def handle(self, request, data): + share_id = self.initial['share_id'] + snapshot_id = data['snapshot'] + try: + manila.share_revert(request, share_id, snapshot_id) + message = _('Share "%(s)s" has been reverted to "%(ss)s" snapshot ' + 'successfully') % {'s': share_id, 'ss': snapshot_id} + messages.success(request, message) + return True + except Exception: + redirect = reverse("horizon:project:shares:index") + exceptions.handle( + request, + _('Unable to revert share to the snapshot.'), + redirect=redirect) diff --git a/manila_ui/dashboards/project/shares/shares/tables.py b/manila_ui/dashboards/project/shares/shares/tables.py index 7c71e369..59e18e0c 100644 --- a/manila_ui/dashboards/project/shares/shares/tables.py +++ b/manila_ui/dashboards/project/shares/shares/tables.py @@ -135,6 +135,26 @@ class ExtendShare(tables.LinkAction): return share.status.lower() in ("available",) +class RevertShare(tables.LinkAction): + name = "revert_share" + verbose_name = _("Revert Share") + url = "horizon:project:shares:revert" + classes = ("ajax-modal", "btn-create") + policy_rules = (("share", "share:revert"),) + + def get_policy_target(self, request, datum=None): + project_id = None + if datum: + project_id = getattr(datum, "os-share-tenant-attr:tenant_id", None) + return {"project_id": project_id} + + def allowed(self, request, share=None): + return ( + share.revert_to_snapshot_support and + share.status.lower() == "available" + ) + + class UpdateRow(tables.Row): ajax = True @@ -162,12 +182,14 @@ class SharesTableBase(tables.DataTable): ("available", True), ("AVAILABLE", True), ("creating", None), ("CREATING", None), ("deleting", None), ("DELETING", None), + ("reverting", None), ("migrating", None), ("migrating_to", None), ("error", False), ("ERROR", False), ("error_deleting", False), ("ERROR_DELETING", False), ("MANAGE_ERROR", False), ("UNMANAGE_ERROR", False), ("extending_error", False), + ("reverting_error", False), ) STATUS_DISPLAY_CHOICES = ( ("available", pgettext_lazy("Current status of share", u"Available")), @@ -191,6 +213,8 @@ class SharesTableBase(tables.DataTable): u"Unmanage Error")), ("extending_error", pgettext_lazy("Current status of share", u"Extending Error")), + ("reverting_error", pgettext_lazy("Current status of share", + u"Reverting Error")), ) name = tables.WrappingColumn( "name", verbose_name=_("Name"), @@ -331,6 +355,7 @@ class SharesTable(SharesTableBase): row_actions = ( EditShare, ExtendShare, + RevertShare, snapshot_tables.CreateSnapshot, ManageRules, ManageReplicas, diff --git a/manila_ui/dashboards/project/shares/shares/views.py b/manila_ui/dashboards/project/shares/shares/views.py index 7fa96814..2ab28bfa 100644 --- a/manila_ui/dashboards/project/shares/shares/views.py +++ b/manila_ui/dashboards/project/shares/shares/views.py @@ -283,3 +283,37 @@ class ExtendView(forms.ModalFormView): 'orig_size': share.size, 'new_size': int(share.size) + 1, } + + +class RevertView(forms.ModalFormView): + form_class = share_form.RevertForm + form_id = "revert_share" + template_name = 'project/shares/shares/revert.html' + modal_header = _("Revert Share to a Snapshot") + modal_id = "revert_share_modal" + submit_label = _("Revert share to a snapshot") + submit_url = "horizon:project:shares:revert" + success_url = reverse_lazy("horizon:project:shares:index") + page_title = _('Revert Share to a Snapshot') + + @memoized.memoized_method + def get_object(self): + try: + return manila.share_get(self.request, self.kwargs['share_id']) + except Exception: + exceptions.handle(self.request, _('Unable to retrieve share.')) + + def get_context_data(self, **kwargs): + context = super(self.__class__, self).get_context_data(**kwargs) + args = (self.get_object().id,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + share = self.get_object() + if not share or isinstance(share, Exception): + raise exceptions.NotFound() + return { + 'share_id': self.kwargs["share_id"], + 'name': share.name or share.id, + } diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/_revert.html b/manila_ui/dashboards/project/shares/templates/shares/shares/_revert.html new file mode 100644 index 00000000..b5d9724d --- /dev/null +++ b/manila_ui/dashboards/project/shares/templates/shares/shares/_revert.html @@ -0,0 +1,6 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} +{% block modal-body-right %} +
{% trans "From here you can revert the share to its latest snapshot." %}
+{% endblock %} diff --git a/manila_ui/dashboards/project/shares/templates/shares/shares/revert.html b/manila_ui/dashboards/project/shares/templates/shares/shares/revert.html new file mode 100644 index 00000000..d5973eb2 --- /dev/null +++ b/manila_ui/dashboards/project/shares/templates/shares/shares/revert.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Revert Share" %}{% endblock %} + +{% block main %} + {% include 'project/shares/shares/_revert.html' %} +{% endblock %} diff --git a/manila_ui/dashboards/project/shares/urls.py b/manila_ui/dashboards/project/shares/urls.py index ac625193..ed8ee9a1 100644 --- a/manila_ui/dashboards/project/shares/urls.py +++ b/manila_ui/dashboards/project/shares/urls.py @@ -79,6 +79,9 @@ urlpatterns = [ url(r'^(?P