horizon/openstack_dashboard/dashboards/admin/volume_types/forms.py

375 lines
16 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.forms import ValidationError
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard.api import cinder
from openstack_dashboard.api import keystone
class CreateVolumeType(forms.SelfHandlingForm):
name = forms.CharField(max_length=255, label=_("Name"))
vol_type_description = forms.CharField(
max_length=255,
widget=forms.Textarea(attrs={'rows': 4}),
label=_("Description"),
required=False)
is_public = forms.BooleanField(
label=_("Public"),
initial=True,
required=False,
help_text=_("By default, volume type is created as public. To "
"create a private volume type, uncheck this field."))
def clean_name(self):
cleaned_name = self.cleaned_data['name']
if cleaned_name.isspace():
raise ValidationError(_('Volume type name can not be empty.'))
return cleaned_name
def handle(self, request, data):
try:
# Remove any new lines in the public key
volume_type = cinder.volume_type_create(
request,
data['name'],
data['vol_type_description'],
data['is_public'])
messages.success(request, _('Successfully created volume type: %s')
% data['name'])
return volume_type
except Exception as e:
if getattr(e, 'code', None) == 409:
msg = _('Volume type name "%s" already '
'exists.') % data['name']
self._errors['name'] = self.error_class([msg])
else:
redirect = reverse("horizon:admin:volume_types:index")
exceptions.handle(request,
_('Unable to create volume type.'),
redirect=redirect)
class CreateQosSpec(forms.SelfHandlingForm):
name = forms.CharField(max_length=255, label=_("Name"))
consumer = forms.ThemableChoiceField(label=_("Consumer"),
choices=cinder.CONSUMER_CHOICES)
def handle(self, request, data):
try:
qos_spec = cinder.qos_spec_create(request,
data['name'],
{'consumer': data['consumer']})
messages.success(request,
_('Successfully created QoS Spec: %s')
% data['name'])
return qos_spec
except Exception as ex:
if getattr(ex, 'code', None) == 409:
msg = _('QoS Spec name "%s" already '
'exists.') % data['name']
self._errors['name'] = self.error_class([msg])
else:
redirect = reverse("horizon:admin:volume_types:index")
exceptions.handle(request,
_('Unable to create QoS Spec.'),
redirect=redirect)
class CreateVolumeTypeEncryption(forms.SelfHandlingForm):
name = forms.CharField(label=_("Name"), required=False,
widget=forms.TextInput(attrs={'readonly':
'readonly'}))
provider = forms.CharField(max_length=255, label=_("Provider"))
control_location = forms.ThemableChoiceField(label=_("Control Location"),
choices=(('front-end',
_('front-end')),
('back-end',
_('back-end')))
)
cipher = forms.CharField(label=_("Cipher"), required=False)
key_size = forms.IntegerField(label=_("Key Size (bits)"),
required=False,
min_value=1)
volume_type_id = forms.CharField(widget=forms.HiddenInput())
def handle(self, request, data):
try:
# Set Cipher to None if empty
if data['cipher'] == '':
data['cipher'] = None
volume_type_id = data.pop('volume_type_id')
volume_type_name = data.pop('name')
# Create encryption for the volume type
volume_type = cinder.\
volume_encryption_type_create(request,
volume_type_id,
data)
messages.success(request, _('Successfully created encryption for '
'volume type: %s') % volume_type_name)
return volume_type
except Exception:
redirect = reverse("horizon:admin:volume_types:index")
exceptions.handle(
request, _('Unable to create encrypted volume type.'),
redirect=redirect)
class UpdateVolumeTypeEncryption(CreateVolumeTypeEncryption):
def handle(self, request, data):
try:
# Set Cipher to None if empty
if data['cipher'] == '':
data['cipher'] = None
volume_type_id = data.pop('volume_type_id')
volume_type_name = data.pop('name')
# Update encryption for the volume type
volume_type = cinder.\
volume_encryption_type_update(request,
volume_type_id,
data)
messages.success(request, _('Successfully updated encryption for '
'volume type: %s') % volume_type_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:volume_types:index")
exceptions.handle(request,
_('Unable to update encrypted volume type.'),
redirect=redirect)
return False
class ManageQosSpecAssociation(forms.SelfHandlingForm):
qos_spec_choice = forms.ThemableChoiceField(
label=_("QoS Spec to be associated"),
help_text=_("Choose associated QoS Spec."))
def __init__(self, request, *args, **kwargs):
super().__init__(request, *args, **kwargs)
qos_spec_field = self.fields['qos_spec_choice']
qos_spec_field.choices = \
self.populate_qos_spec_choices()
def populate_qos_spec_choices(self):
# populate qos spec list box
qos_specs = self.initial["qos_specs"]
current_qos_spec = self.initial["cur_qos_spec_id"]
qos_spec_list = [(qos_spec.id, qos_spec.name)
for qos_spec in qos_specs
if qos_spec.id != current_qos_spec]
if current_qos_spec:
# used to remove the current spec
qos_spec_list.insert(0, ("-1", _("None (removes spec)")))
if qos_spec_list:
qos_spec_list.insert(0, ("", _("Select a new QoS spec")))
else:
qos_spec_list.insert(0, ("", _("No new QoS spec available")))
return qos_spec_list
def handle(self, request, data):
vol_type_id = self.initial['type_id']
new_qos_spec_id = data['qos_spec_choice']
# Update QOS Spec association information
try:
# NOTE - volume types can only be associated with
# ONE QOS Spec at a time
# first we need to un-associate the current QOS Spec, if it exists
cur_qos_spec_id = self.initial['cur_qos_spec_id']
if cur_qos_spec_id:
qos_spec = cinder.qos_spec_get(request,
cur_qos_spec_id)
cinder.qos_spec_disassociate(request,
qos_spec,
vol_type_id)
# now associate with new QOS Spec, if user wants one associated
if new_qos_spec_id != '-1':
qos_spec = cinder.qos_spec_get(request,
new_qos_spec_id)
cinder.qos_spec_associate(request,
qos_spec,
vol_type_id)
messages.success(request,
_('Successfully updated QoS Spec association.'))
return True
except Exception:
redirect = reverse("horizon:admin:volume_types:index")
exceptions.handle(request,
_('Error updating QoS Spec association.'),
redirect=redirect)
class EditQosSpecConsumer(forms.SelfHandlingForm):
current_consumer = forms.CharField(label=_("Current consumer"),
widget=forms.TextInput(
attrs={'readonly': 'readonly'}),
required=False)
consumer_choice = forms.ThemableChoiceField(
label=_("New QoS Spec Consumer"),
choices=cinder.CONSUMER_CHOICES,
help_text=_("Choose consumer for this QoS Spec."))
def __init__(self, request, *args, **kwargs):
super().__init__(request, *args, **kwargs)
consumer_field = self.fields['consumer_choice']
qos_spec = self.initial["qos_spec"]
self.fields['current_consumer'].initial = qos_spec.consumer
choices = [choice for choice in cinder.CONSUMER_CHOICES
if choice[0] != qos_spec.consumer]
choices.insert(0, ("", _("Select a new consumer")))
consumer_field.choices = choices
def handle(self, request, data):
qos_spec_id = self.initial['qos_spec_id']
new_consumer = data['consumer_choice']
# Update QOS Spec consumer information
try:
cinder.qos_spec_set_keys(request,
qos_spec_id,
{'consumer': new_consumer})
messages.success(request,
_('Successfully modified QoS Spec consumer.'))
return True
except Exception:
redirect = reverse("horizon:admin:volume_types:index")
exceptions.handle(request, _('Error editing QoS Spec consumer.'),
redirect=redirect)
class EditVolumeType(forms.SelfHandlingForm):
name = forms.CharField(max_length=255,
label=_("Name"))
description = forms.CharField(max_length=255,
widget=forms.Textarea(attrs={'rows': 4}),
label=_("Description"),
required=False)
is_public = forms.BooleanField(label=_("Public"), required=False,
help_text=_(
"To make volume type private, uncheck "
"this field."))
def clean_name(self):
cleaned_name = self.cleaned_data['name']
if cleaned_name.isspace():
msg = _('New name cannot be empty.')
self._errors['name'] = self.error_class([msg])
return cleaned_name
def handle(self, request, data):
volume_type_id = self.initial['id']
try:
cinder.volume_type_update(request,
volume_type_id,
data['name'],
data['description'],
data['is_public'])
message = _('Successfully updated volume type.')
messages.success(request, message)
return True
except Exception as ex:
redirect = reverse("horizon:admin:volume_types:index")
if ex.code == 409:
error_message = _('New name conflicts with another '
'volume type.')
else:
error_message = _('Unable to update volume type.')
exceptions.handle(request, error_message,
redirect=redirect)
class EditTypeAccessForm(forms.SelfHandlingForm):
def __init__(self, request, *args, **kwargs):
super().__init__(request, *args, **kwargs)
err_msg = _('Unable to retrieve volume type access list.')
self.fields["member"] = forms.MultipleChoiceField(
required=False,
widget=forms.ThemableCheckboxSelectMultiple())
# Get list of available projects.
try:
all_projects, has_more = keystone.tenant_list(request)
except Exception:
exceptions.handle(request, err_msg)
projects_list = [(project.id, project.name)
for project in all_projects]
self.fields["member"].choices = projects_list
volume_type_id = self.initial.get('volume_type_id')
volume_type_access = []
try:
if volume_type_id:
volume_type = cinder.volume_type_get(request,
volume_type_id)
if not volume_type.is_public:
volume_type_access = [
project.project_id for project in
cinder.volume_type_access_list(request,
volume_type_id)]
except Exception:
exceptions.handle(request, err_msg)
self.fields["member"].initial = volume_type_access
def handle(self, request, data):
type_id = self.initial['volume_type_id']
current_projects = self.fields["member"].initial
removed_projects = current_projects
for p in data['member']:
if p not in current_projects:
# Newly added project access
try:
cinder.volume_type_add_project_access(request, type_id, p)
except Exception:
exceptions.handle(request,
_('Failed to add project %(project)s to '
'volume type access.') %
{'project': p})
else:
removed_projects.remove(p)
for p in removed_projects:
try:
cinder.volume_type_remove_project_access(request, type_id, p)
except Exception:
exceptions.handle(request, _('Failed to remove project '
'%(project)s from volume type '
'access.') % {'project': p})
messages.success(request,
_('Modified volume type access: %s') % type_id)
return True