Add volume type encryption update
This patch adds support to horizon for volume type encryption update. The modifications are made to the Admin Volume Type table, and add the Update Encryption action to the action column. Implements: blueprint integration-with-cinder-volume-encryption Change-Id: I7b6f1db60818a07feb64eaa464e64397ea477a7b
This commit is contained in:
parent
1178757445
commit
4e61f626e4
@ -521,6 +521,11 @@ def volume_encryption_type_list(request):
|
||||
return cinderclient(request).volume_encryption_types.list()
|
||||
|
||||
|
||||
def volume_encryption_type_update(request, volume_type_id, data):
|
||||
return cinderclient(request).volume_encryption_types.update(volume_type_id,
|
||||
specs=data)
|
||||
|
||||
|
||||
def volume_type_extra_get(request, type_id, raw=False):
|
||||
vol_type = volume_type_get(request, type_id)
|
||||
extras = vol_type.get_keys()
|
||||
|
@ -0,0 +1,21 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>
|
||||
{% trans "Encryption information cannot be updated for a volume type if volumes are currently in use with the volume type." %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}The <strong>Provider</strong> is the class providing encryption support (e.g., LuksEncryptor).{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}The <strong>Control Location</strong> is the notional service where encryption is performed (e.g., front-end=Nova). The default value is 'front-end.'{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}The <strong>Cipher</strong> is the encryption algorithm/mode to use (e.g., aes-xts-plain64). If the field is left empty, the provider default will be used.{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}The <strong>Key Size</strong> is the size of the encryption key, in bits (e.g., 128, 256). If the field is left empty, the provider default will be used.{% endblocktrans %}
|
||||
</p>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Encrypted Volume Type" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/volumes/volume_types/_update_volume_type_encryption.html' %}
|
||||
{% endblock %}
|
@ -104,7 +104,7 @@ class CreateVolumeTypeEncryption(forms.SelfHandlingForm):
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
# Set Cipher to None if empty
|
||||
if data['cipher'] is u'':
|
||||
if data['cipher'] == u'':
|
||||
data['cipher'] = None
|
||||
|
||||
# Create encryption for the volume type
|
||||
@ -122,6 +122,34 @@ class CreateVolumeTypeEncryption(forms.SelfHandlingForm):
|
||||
redirect=redirect)
|
||||
|
||||
|
||||
class UpdateVolumeTypeEncryption(CreateVolumeTypeEncryption):
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
# Set Cipher to None if empty
|
||||
if data['cipher'] == u'':
|
||||
data['cipher'] = None
|
||||
|
||||
# Update encryption for the volume type
|
||||
volume_type = cinder.\
|
||||
volume_encryption_type_update(request,
|
||||
data['volume_type_id'],
|
||||
data)
|
||||
messages.success(request, _('Successfully updated encryption for '
|
||||
'volume type: %s') % data['name'])
|
||||
return volume_type
|
||||
except NotImplementedError:
|
||||
messages.error(request, _('Updating encryption is not '
|
||||
'implemented. Unable to update '
|
||||
' encrypted volume type.'))
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:volumes:index")
|
||||
exceptions.handle(request,
|
||||
_('Unable to update encrypted volume type.'),
|
||||
redirect=redirect)
|
||||
return False
|
||||
|
||||
|
||||
class ManageQosSpecAssociation(forms.SelfHandlingForm):
|
||||
qos_spec_choice = forms.ChoiceField(
|
||||
label=_("QoS Spec to be associated"),
|
||||
|
@ -89,11 +89,21 @@ class CreateVolumeTypeEncryption(tables.LinkAction):
|
||||
policy_rules = (("volume", "volume_extension:volume_type_encryption"),)
|
||||
|
||||
def allowed(self, request, volume_type):
|
||||
if _is_vol_type_enc_possible(request):
|
||||
return (hasattr(volume_type, 'encryption')
|
||||
and not hasattr(volume_type.encryption, 'provider'))
|
||||
else:
|
||||
return False
|
||||
return (_is_vol_type_enc_possible(request) and
|
||||
not _does_vol_type_enc_exist(volume_type))
|
||||
|
||||
|
||||
class UpdateVolumeTypeEncryption(tables.LinkAction):
|
||||
name = "update_encryption"
|
||||
verbose_name = _("Update Encryption")
|
||||
url = "horizon:admin:volumes:volume_types:update_type_encryption"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("volume", "volume_extension:volume_type_encryption"),)
|
||||
|
||||
def allowed(self, request, volume_type=None):
|
||||
return (_is_vol_type_enc_possible(request) and
|
||||
_does_vol_type_enc_exist(volume_type))
|
||||
|
||||
|
||||
class DeleteVolumeTypeEncryption(tables.DeleteAction):
|
||||
@ -122,8 +132,14 @@ class DeleteVolumeTypeEncryption(tables.DeleteAction):
|
||||
|
||||
def allowed(self, request, volume_type=None):
|
||||
return (_is_vol_type_enc_possible(request) and
|
||||
hasattr(volume_type, 'encryption') and
|
||||
hasattr(volume_type.encryption, 'provider'))
|
||||
_does_vol_type_enc_exist(volume_type))
|
||||
|
||||
|
||||
def _does_vol_type_enc_exist(volume_type):
|
||||
# Check to see if there is an existing encryption information
|
||||
# for the volume type or not
|
||||
return (hasattr(volume_type, 'encryption') and
|
||||
hasattr(volume_type.encryption, 'provider'))
|
||||
|
||||
|
||||
def _is_vol_type_enc_possible(request):
|
||||
@ -235,6 +251,7 @@ class VolumeTypesTable(tables.DataTable):
|
||||
ViewVolumeTypeExtras,
|
||||
ManageQosSpecAssociation,
|
||||
EditVolumeType,
|
||||
UpdateVolumeTypeEncryption,
|
||||
DeleteVolumeTypeEncryption,
|
||||
DeleteVolumeType,)
|
||||
row_class = UpdateRow
|
||||
|
@ -226,3 +226,39 @@ class VolumeTypeTests(test.BaseAdminViewTests):
|
||||
redirect = reverse('horizon:admin:volumes:volume_types_tab')
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, redirect)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_encryption_type_update',
|
||||
'volume_encryption_type_get',
|
||||
'volume_type_list')})
|
||||
def test_update_volume_type_encryption(self):
|
||||
volume_type = self.volume_types.first()
|
||||
volume_type.id = u'1'
|
||||
volume_type_list = [volume_type]
|
||||
formData = {'name': u'An Encrypted Volume Type',
|
||||
'provider': u'a-provider',
|
||||
'control_location': u'front-end',
|
||||
'cipher': u'a-cipher',
|
||||
'key_size': 256,
|
||||
'volume_type_id': volume_type.id}
|
||||
vol_enc_type = self.cinder_volume_encryption_types.list()[0]
|
||||
|
||||
cinder.volume_encryption_type_get(IsA(http.HttpRequest),
|
||||
volume_type.id)\
|
||||
.AndReturn(vol_enc_type)
|
||||
cinder.volume_type_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(volume_type_list)
|
||||
cinder.volume_encryption_type_update(IsA(http.HttpRequest),
|
||||
formData['volume_type_id'],
|
||||
formData)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:'
|
||||
'volume_types:update_type_encryption',
|
||||
args=[volume_type.id])
|
||||
res = self.client.post(url, formData)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertTemplateUsed(
|
||||
res,
|
||||
'admin/volumes/volume_types/update_volume_type_encryption.html')
|
||||
|
@ -43,6 +43,9 @@ urlpatterns = patterns(
|
||||
url(r'^(?P<volume_type_id>[^/]+)/create_type_encryption/$',
|
||||
views.CreateVolumeTypeEncryptionView.as_view(),
|
||||
name='create_type_encryption'),
|
||||
url(r'^(?P<volume_type_id>[^/]+)/update_type_encryption/$',
|
||||
views.UpdateVolumeTypeEncryptionView.as_view(),
|
||||
name='update_type_encryption'),
|
||||
url(r'^(?P<volume_type_id>[^/]+)/type_encryption_detail/$',
|
||||
views.VolumeTypeEncryptionDetailView.as_view(),
|
||||
name='type_encryption_detail'),
|
||||
|
@ -86,15 +86,8 @@ class CreateVolumeTypeEncryptionView(forms.ModalFormView):
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_name(self):
|
||||
try:
|
||||
volume_type_list = api.cinder.volume_type_list(self.request)
|
||||
for volume_type in volume_type_list:
|
||||
if volume_type.id == self.kwargs['volume_type_id']:
|
||||
self.name = volume_type.name
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve volume type name.')
|
||||
url = reverse('horizon:admin:volumes:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
if not hasattr(self, "name"):
|
||||
self.name = _get_volume_type_name(self.request, self.kwargs)
|
||||
return self.name
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -147,6 +140,67 @@ class EditVolumeTypeView(forms.ModalFormView):
|
||||
'description': getattr(volume_type, 'description', "")}
|
||||
|
||||
|
||||
def _get_volume_type_name(request, kwargs):
|
||||
try:
|
||||
volume_type_list = api.cinder.volume_type_list(request)
|
||||
for volume_type in volume_type_list:
|
||||
if volume_type.id == kwargs['volume_type_id']:
|
||||
return volume_type.name
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve volume type name.')
|
||||
url = reverse('horizon:admin:volumes:index')
|
||||
exceptions.handle(request, msg, redirect=url)
|
||||
|
||||
|
||||
class UpdateVolumeTypeEncryptionView(forms.ModalFormView):
|
||||
form_class = volume_types_forms.UpdateVolumeTypeEncryption
|
||||
form_id = "update_volume_form"
|
||||
modal_header = _("Update Volume Type Encryption")
|
||||
modal_id = "update_volume_type_modal"
|
||||
template_name = ("admin/volumes/volume_types/"
|
||||
"update_volume_type_encryption.html")
|
||||
page_title = _("Update an Encrypted Volume Type")
|
||||
submit_label = _("Update Volume Type Encryption")
|
||||
submit_url = "horizon:admin:volumes:volume_types:update_type_encryption"
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
try:
|
||||
self._object = api.cinder.\
|
||||
volume_encryption_type_get(self.request,
|
||||
self.kwargs['volume_type_id'])
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve encryption type.')
|
||||
url = reverse('horizon:admin:volumes:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_name(self):
|
||||
if not hasattr(self, "name"):
|
||||
self.name = _get_volume_type_name(self.request, self.kwargs)
|
||||
return self.name
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateVolumeTypeEncryptionView, self).\
|
||||
get_context_data(**kwargs)
|
||||
context['volume_type_id'] = self.kwargs['volume_type_id']
|
||||
args = (self.kwargs['volume_type_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
encryption_type = self.get_object()
|
||||
name = self.get_name()
|
||||
return {'volume_type_id': encryption_type.volume_type_id,
|
||||
'control_location': encryption_type.control_location,
|
||||
'key_size': encryption_type.key_size,
|
||||
'provider': encryption_type.provider,
|
||||
'cipher': encryption_type.cipher,
|
||||
'name': name}
|
||||
|
||||
|
||||
class CreateQosSpecView(forms.ModalFormView):
|
||||
form_class = volume_types_forms.CreateQosSpec
|
||||
modal_header = _("Create QoS Spec")
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Added the Update Encryption action for encrypted volume types.
|
Loading…
Reference in New Issue
Block a user