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:
parent
d8b8284c7b
commit
04494e8678
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue