Add update method of snapshot name and description
Change-Id: I0c396bee1f14bdb96812012ea89d6fd2bf0c6e34 Closes-Bug: #1265140 Closes-Bug: #1296398
This commit is contained in:
parent
62c766754d
commit
235ceff89c
|
@ -222,6 +222,14 @@ def volume_snapshot_delete(request, snapshot_id):
|
|||
return cinderclient(request).volume_snapshots.delete(snapshot_id)
|
||||
|
||||
|
||||
def volume_snapshot_update(request, snapshot_id, name, description):
|
||||
snapshot_data = {'name': name,
|
||||
'description': description}
|
||||
snapshot_data = _replace_v2_parameters(snapshot_data)
|
||||
return cinderclient(request).volume_snapshots.update(snapshot_id,
|
||||
**snapshot_data)
|
||||
|
||||
|
||||
def tenant_quota_get(request, tenant_id):
|
||||
c_client = cinderclient(request)
|
||||
if c_client is None:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"volume:create_snapshot": [["rule:default"]],
|
||||
"volume:delete_snapshot": [["rule:default"]],
|
||||
"volume:get_snapshot": [],
|
||||
"volume:update_snapshot": [["rule:default"]],
|
||||
"volume:get_all_snapshots": [],
|
||||
"volume:extend": [],
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# 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.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from openstack_dashboard.api import cinder
|
||||
|
||||
|
||||
class UpdateForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(max_length="255", label=_("Snapshot Name"))
|
||||
description = forms.CharField(widget=forms.Textarea,
|
||||
label=_("Description"), required=False)
|
||||
|
||||
def handle(self, request, data):
|
||||
snapshot_id = self.initial['snapshot_id']
|
||||
try:
|
||||
cinder.volume_snapshot_update(request,
|
||||
snapshot_id,
|
||||
data['name'],
|
||||
data['description'])
|
||||
|
||||
message = _('Updating volume snapshot "%s"') % data['name']
|
||||
messages.info(request, message)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:project:volumes:index")
|
||||
exceptions.handle(request,
|
||||
_('Unable to update volume snapshot.'),
|
||||
redirect=redirect)
|
|
@ -60,6 +60,25 @@ class DeleteVolumeSnapshot(tables.DeleteAction):
|
|||
api.cinder.volume_snapshot_delete(request, obj_id)
|
||||
|
||||
|
||||
class EditVolumeSnapshot(tables.LinkAction):
|
||||
name = "edit"
|
||||
verbose_name = _("Edit Snapshot")
|
||||
url = "horizon:project:volumes:snapshots:update"
|
||||
classes = ("ajax-modal", "btn-edit")
|
||||
policy_rules = (("volume", "volume:update_snapshot"),)
|
||||
|
||||
def get_policy_target(self, request, datum=None):
|
||||
project_id = None
|
||||
if datum:
|
||||
project_id = getattr(datum,
|
||||
"os-extended-snapshot-attributes:project_id",
|
||||
None)
|
||||
return {"project_id": project_id}
|
||||
|
||||
def allowed(self, request, snapshot=None):
|
||||
return snapshot.status == "available"
|
||||
|
||||
|
||||
class CreateVolumeFromSnapshot(tables.LinkAction):
|
||||
name = "create_from_snapshot"
|
||||
verbose_name = _("Create Volume")
|
||||
|
@ -107,8 +126,9 @@ class SnapshotVolumeNameColumn(tables.Column):
|
|||
class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:project:volumes:detail")
|
||||
volume_name = SnapshotVolumeNameColumn("name",
|
||||
link="horizon:project:volumes:snapshots:detail")
|
||||
volume_name = SnapshotVolumeNameColumn(
|
||||
"name",
|
||||
verbose_name=_("Volume Name"),
|
||||
link="horizon:project:volumes:volumes:detail")
|
||||
|
||||
|
@ -117,7 +137,7 @@ class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
|
|||
verbose_name = _("Volume Snapshots")
|
||||
table_actions = (DeleteVolumeSnapshot,)
|
||||
row_actions = (CreateVolumeFromSnapshot, LaunchSnapshot,
|
||||
DeleteVolumeSnapshot)
|
||||
EditVolumeSnapshot, DeleteVolumeSnapshot)
|
||||
row_class = UpdateRow
|
||||
status_columns = ("status",)
|
||||
permissions = ['openstack.services.volume']
|
||||
|
|
|
@ -153,7 +153,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:project:volumes:detail',
|
||||
url = reverse('horizon:project:volumes:snapshots:detail',
|
||||
args=[snapshot.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
|
@ -174,7 +174,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
AndRaise(self.exceptions.cinder)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:project:volumes:detail',
|
||||
url = reverse('horizon:project:volumes:snapshots:detail',
|
||||
args=[snapshot.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
|
@ -193,8 +193,30 @@ class VolumeSnapshotsViewTests(test.TestCase):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:project:volumes:detail',
|
||||
url = reverse('horizon:project:volumes:snapshots:detail',
|
||||
args=[snapshot.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_snapshot_update',
|
||||
'volume_snapshot_get')})
|
||||
def test_update_snapshot(self):
|
||||
snapshot = self.cinder_volume_snapshots.first()
|
||||
|
||||
cinder.volume_snapshot_get(IsA(http.HttpRequest), snapshot.id) \
|
||||
.AndReturn(snapshot)
|
||||
cinder.volume_snapshot_update(IsA(http.HttpRequest),
|
||||
snapshot.id,
|
||||
snapshot.name,
|
||||
snapshot.description) \
|
||||
.AndReturn(snapshot)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'method': 'UpdateSnapshotForm',
|
||||
'name': snapshot.name,
|
||||
'description': snapshot.description}
|
||||
url = reverse(('horizon:project:volumes:snapshots:update'),
|
||||
args=[snapshot.id])
|
||||
res = self.client.post(url, formData)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# 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.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.project.volumes.snapshots import views
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^(?P<snapshot_id>[^/]+)$',
|
||||
views.DetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'^(?P<snapshot_id>[^/]+)/update/$',
|
||||
views.UpdateView.as_view(),
|
||||
name='update'),
|
||||
)
|
|
@ -0,0 +1,83 @@
|
|||
# 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.core.urlresolvers import reverse
|
||||
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 horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
.snapshots import forms as vol_snapshot_forms
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
.snapshots import tabs as vol_snapshot_tabs
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = vol_snapshot_forms.UpdateForm
|
||||
template_name = 'project/volumes/snapshots/update.html'
|
||||
success_url = reverse_lazy("horizon:project:volumes:index")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_object(self):
|
||||
snap_id = self.kwargs['snapshot_id']
|
||||
try:
|
||||
self._object = api.cinder.volume_snapshot_get(self.request,
|
||||
snap_id)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve volume snapshot.')
|
||||
url = reverse('horizon:project:volumes:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
context['snapshot'] = self.get_object()
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
snapshot = self.get_object()
|
||||
return {'snapshot_id': self.kwargs["snapshot_id"],
|
||||
'name': snapshot.name,
|
||||
'description': snapshot.description}
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
tab_group_class = vol_snapshot_tabs.SnapshotDetailTabs
|
||||
template_name = 'project/volumes/snapshots/detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
context["snapshot"] = self.get_data()
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
snapshot_id = self.kwargs['snapshot_id']
|
||||
snapshot = api.cinder.volume_snapshot_get(self.request,
|
||||
snapshot_id)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:project:volumes:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve snapshot details.'),
|
||||
redirect=redirect)
|
||||
return snapshot
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
snapshot = self.get_data()
|
||||
return self.tab_group_class(request, snapshot=snapshot, **kwargs)
|
|
@ -0,0 +1,26 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
|
||||
{% block form_id %}update_snapshot_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:project:volumes:snapshots:update' snapshot.id %}{% endblock %}
|
||||
|
||||
{% block modal_id %}update_snapshot_modal{% endblock %}
|
||||
{% block modal-header %}{% trans "Edit Snapshot" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>{% trans "From here you can modify the name and description of a snapshot." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Edit Snapshot" %}" />
|
||||
<a href="{% url 'horizon:project:volumes:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -0,0 +1,11 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Edit Snapshot" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Edit Snapshot") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/volumes/snapshots/_update.html' %}
|
||||
{% endblock %}
|
|
@ -18,6 +18,8 @@ from django.conf.urls import include # noqa
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.project.volumes.snapshots \
|
||||
import urls as snapshot_urls
|
||||
from openstack_dashboard.dashboards.project.volumes import views
|
||||
from openstack_dashboard.dashboards.project.volumes.volumes \
|
||||
import urls as volume_urls
|
||||
|
@ -30,7 +32,5 @@ urlpatterns = patterns('',
|
|||
url(r'^\?tab=volumes_and_snapshots__volumes_tab$',
|
||||
views.IndexView.as_view(), name='volumes_tab'),
|
||||
url(r'', include(volume_urls, namespace='volumes')),
|
||||
url(r'^snapshots/(?P<snapshot_id>[^/]+)/$',
|
||||
views.DetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'snapshots/', include(snapshot_urls, namespace='snapshots')),
|
||||
)
|
||||
|
|
|
@ -14,47 +14,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard.api import cinder
|
||||
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
import tabs as project_tabs
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
.snapshots import tabs as vol_snapshot_tabs
|
||||
|
||||
|
||||
class IndexView(tabs.TabbedTableView):
|
||||
tab_group_class = project_tabs.VolumeAndSnapshotTabs
|
||||
template_name = 'project/volumes/index.html'
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
tab_group_class = vol_snapshot_tabs.SnapshotDetailTabs
|
||||
template_name = 'project/volumes/snapshots/detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
context["snapshot"] = self.get_data()
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
snapshot_id = self.kwargs['snapshot_id']
|
||||
snapshot = cinder.volume_snapshot_get(self.request, snapshot_id)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:project:volumes:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve snapshot details.'),
|
||||
redirect=redirect)
|
||||
return snapshot
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
snapshot = self.get_data()
|
||||
return self.tab_group_class(request, snapshot=snapshot, **kwargs)
|
||||
|
|
Loading…
Reference in New Issue