Allowing snapshoting attached volume

The cinder api allows calling snapshot on attached volumes,
we should enable it on horizon.

Change-Id: I33d7bbca0bf993ace7c243867aa5f57438a57a5d
Fixes: bug #1202929
This commit is contained in:
Zhenguo Niu 2013-11-19 10:39:37 +08:00
parent d8b8284c7b
commit 04494e8678
6 changed files with 67 additions and 10 deletions

View File

@ -116,9 +116,11 @@ def volume_snapshot_list(request):
return c_client.volume_snapshots.list()
def volume_snapshot_create(request, volume_id, name, description):
def volume_snapshot_create(request, volume_id, name,
description=None, force=False):
return cinderclient(request).volume_snapshots.create(
volume_id, display_name=name, display_description=description)
volume_id, force=force, display_name=name,
display_description=description)
def volume_snapshot_delete(request, snapshot_id):

View File

@ -32,9 +32,12 @@ INDEX_URL = reverse('horizon:project:images_and_snapshots:index')
class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({quotas: ('tenant_limit_usages',)})
@test.create_stubs({cinder: ('volume_get',),
quotas: ('tenant_limit_usages',)})
def test_create_snapshot_get(self):
volume = self.volumes.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
'volumesUsed': len(self.volumes.list()),
@ -49,15 +52,45 @@ class VolumeSnapshotsViewTests(test.TestCase):
self.assertTemplateUsed(res, 'project/volumes/create_snapshot.html')
@test.create_stubs({cinder: ('volume_snapshot_create',)})
@test.create_stubs({cinder: ('volume_get',
'volume_snapshot_create',)})
def test_create_snapshot_post(self):
volume = self.volumes.first()
snapshot = self.volume_snapshots.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
cinder.volume_snapshot_create(IsA(http.HttpRequest),
volume.id,
snapshot.display_name,
snapshot.display_description) \
snapshot.display_description,
force=False) \
.AndReturn(snapshot)
self.mox.ReplayAll()
formData = {'method': 'CreateSnapshotForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
'name': snapshot.display_name,
'description': snapshot.display_description}
url = reverse('horizon:project:volumes:create_snapshot',
args=[volume.id])
res = self.client.post(url, formData)
self.assertRedirectsNoFollow(res, INDEX_URL)
@test.create_stubs({cinder: ('volume_get',
'volume_snapshot_create',)})
def test_force_create_snapshot(self):
volume = self.volumes.get(name='my_volume')
snapshot = self.volume_snapshots.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
cinder.volume_snapshot_create(IsA(http.HttpRequest),
volume.id,
snapshot.display_name,
snapshot.display_description,
force=True) \
.AndReturn(snapshot)
self.mox.ReplayAll()

View File

@ -379,12 +379,20 @@ class CreateSnapshotForm(forms.SelfHandlingForm):
def handle(self, request, data):
try:
volume = cinder.volume_get(request,
data['volume_id'])
force = False
message = _('Creating volume snapshot "%s".') % data['name']
if volume.status == 'in-use':
force = True
message = _('Forcing to create snapshot "%s" '
'from attached volume.') % data['name']
snapshot = cinder.volume_snapshot_create(request,
data['volume_id'],
data['name'],
data['description'])
data['description'],
force=force)
message = _('Creating volume snapshot "%s"') % data['name']
messages.info(request, message)
return snapshot
except Exception:

View File

@ -94,7 +94,7 @@ class CreateSnapshot(tables.LinkAction):
classes = ("ajax-modal", "btn-camera")
def allowed(self, request, volume=None):
return volume.status == "available"
return volume.status in ("available", "in-use")
class UpdateRow(tables.Row):

View File

@ -20,6 +20,10 @@
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Volume Snapshot" %}" />
{% if attached %}
<input class="btn btn-primary btn-warning pull-right" type="submit" value="{% trans "Create Volume Snapshot (Force)" %}" />
{% else %}
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Volume Snapshot" %}" />
{% endif %}
<a href="{% url 'horizon:project:volumes:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -141,9 +141,19 @@ class CreateSnapshotView(forms.ModalFormView):
context = super(CreateSnapshotView, self).get_context_data(**kwargs)
context['volume_id'] = self.kwargs['volume_id']
try:
volume = cinder.volume_get(self.request, context['volume_id'])
if (volume.status == 'in-use'):
context['attached'] = True
context['form'].set_warning(_("This volume is currently "
"attached to an instance. "
"In some cases, creating a "
"snapshot from an attached "
"volume can result in a "
"corrupted snapshot."))
context['usages'] = quotas.tenant_limit_usages(self.request)
except Exception:
exceptions.handle(self.request)
exceptions.handle(self.request,
_('Unable to retrieve volume information.'))
return context
def get_initial(self):