Merge "Add volume type encryption update"

This commit is contained in:
Jenkins 2016-02-12 05:59:11 +00:00 committed by Gerrit Code Review
commit 91e1b6dfbc
9 changed files with 191 additions and 17 deletions

View File

@ -562,6 +562,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()

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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"),

View File

@ -94,11 +94,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):
@ -127,8 +137,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):
@ -240,6 +256,7 @@ class VolumeTypesTable(tables.DataTable):
ViewVolumeTypeExtras,
ManageQosSpecAssociation,
EditVolumeType,
UpdateVolumeTypeEncryption,
DeleteVolumeTypeEncryption,
DeleteVolumeType,)
row_class = UpdateRow

View File

@ -261,3 +261,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')

View File

@ -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'),

View File

@ -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")

View File

@ -0,0 +1,3 @@
---
features:
- Added the Update Encryption action for encrypted volume types.