Merge "Add volume type encryption update"
This commit is contained in:
commit
91e1b6dfbc
@ -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()
|
||||
|
@ -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"),
|
||||
|
@ -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,7 +137,13 @@ class DeleteVolumeTypeEncryption(tables.DeleteAction):
|
||||
|
||||
def allowed(self, request, volume_type=None):
|
||||
return (_is_vol_type_enc_possible(request) and
|
||||
hasattr(volume_type, 'encryption') and
|
||||
_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'))
|
||||
|
||||
|
||||
@ -240,6 +256,7 @@ class VolumeTypesTable(tables.DataTable):
|
||||
ViewVolumeTypeExtras,
|
||||
ManageQosSpecAssociation,
|
||||
EditVolumeType,
|
||||
UpdateVolumeTypeEncryption,
|
||||
DeleteVolumeTypeEncryption,
|
||||
DeleteVolumeType,)
|
||||
row_class = UpdateRow
|
||||
|
@ -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')
|
||||
|
@ -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