Files
horizon/openstack_dashboard/dashboards/project/volume_groups/workflows.py
manchandavishal 74760876a9 Remove unnecessary variables
These variables are not used anymore.
This patch removes them.

Change-Id: Id8035412a4f30b1b297acd71cda1d4eff61f5399
2019-05-08 06:58:54 +00:00

381 lines
15 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.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.api import cinder
INDEX_URL = "horizon:project:volume_groups:index"
def cinder_az_supported(request):
try:
return cinder.extension_supported(request, 'AvailabilityZones')
except Exception:
exceptions.handle(request, _('Unable to determine if availability '
'zones extension is supported.'))
return False
def availability_zones(request):
zone_list = []
if cinder_az_supported(request):
try:
zones = api.cinder.availability_zone_list(request)
zone_list = [(zone.zoneName, zone.zoneName)
for zone in zones if zone.zoneState['available']]
zone_list.sort()
except Exception:
exceptions.handle(request, _('Unable to retrieve availability '
'zones.'))
if not zone_list:
zone_list.insert(0, ("", _("No availability zones found")))
elif len(zone_list) > 1:
zone_list.insert(0, ("", _("Any Availability Zone")))
return zone_list
class AddGroupInfoAction(workflows.Action):
name = forms.CharField(label=_("Name"),
max_length=255)
description = forms.CharField(widget=forms.widgets.Textarea(
attrs={'rows': 4}),
label=_("Description"),
required=False)
group_type = forms.ChoiceField(
label=_("Group Type"),
widget=forms.ThemableSelectWidget())
availability_zone = forms.ChoiceField(
label=_("Availability Zone"),
required=False,
widget=forms.ThemableSelectWidget(
attrs={'class': 'switched',
'data-switch-on': 'source',
'data-source-no_source_type': _('Availability Zone'),
'data-source-image_source': _('Availability Zone')}))
def __init__(self, request, *args, **kwargs):
super(AddGroupInfoAction, self).__init__(request,
*args,
**kwargs)
self.fields['availability_zone'].choices = \
availability_zones(request)
try:
# Group type name 'default_cgsnapshot_type' is reserved for
# consistency group and it cannot be used for a group type.
# Let's exclude it.
group_types = [(t.id, t.name) for t
in api.cinder.group_type_list(request)
if t.name != 'default_cgsnapshot_type']
except Exception:
exceptions.handle(request, _('Unable to retrieve group types.'))
if group_types:
group_types.insert(0, ("", _("Select group type")))
else:
group_types.insert(0, ("", _("No valid group type")))
self.fields['group_type'].choices = group_types
class Meta(object):
name = _("Group Information")
help_text = _("Volume groups provide a mechanism for "
"creating snapshots of multiple volumes at the same "
"point-in-time to ensure data consistency\n\n"
"A volume group can support more than one volume "
"type, but it can only contain volumes hosted by the "
"same back end.")
slug = "set_group_info"
def clean(self):
cleaned_data = super(AddGroupInfoAction, self).clean()
name = cleaned_data.get('name')
try:
groups = cinder.group_list(self.request)
except Exception:
msg = _('Unable to get group list')
exceptions.check_message(["Connection", "refused"], msg)
raise
if groups is not None and name is not None:
for group in groups:
if group.name.lower() == name.lower():
# ensure new name has reasonable length
formatted_name = name
if len(name) > 20:
formatted_name = name[:14] + "..." + name[-3:]
raise forms.ValidationError(
_('The name "%s" is already used by '
'another group.')
% formatted_name
)
return cleaned_data
class AddGroupInfoStep(workflows.Step):
action_class = AddGroupInfoAction
contributes = ("availability_zone", "group_type",
"description",
"name")
class AddVolumeTypesToGroupAction(workflows.MembershipAction):
def __init__(self, request, *args, **kwargs):
super(AddVolumeTypesToGroupAction, self).__init__(request,
*args,
**kwargs)
err_msg = _('Unable to get the available volume types')
default_role_field_name = self.get_default_role_field_name()
self.fields[default_role_field_name] = forms.CharField(required=False)
self.fields[default_role_field_name].initial = 'member'
field_name = self.get_member_field_name('member')
self.fields[field_name] = forms.MultipleChoiceField(required=False)
vtypes = []
try:
vtypes = cinder.volume_type_list(request)
except Exception:
exceptions.handle(request, err_msg)
vtype_list = [(vtype.id, vtype.name)
for vtype in vtypes]
self.fields[field_name].choices = vtype_list
class Meta(object):
name = _("Manage Volume Types")
slug = "add_vtypes_to_group"
def clean(self):
cleaned_data = super(AddVolumeTypesToGroupAction, self).clean()
volume_types = cleaned_data.get('add_vtypes_to_group_role_member')
if not volume_types:
raise forms.ValidationError(
_('At least one volume type must be assigned '
'to a group.')
)
return cleaned_data
class AddVolTypesToGroupStep(workflows.UpdateMembersStep):
action_class = AddVolumeTypesToGroupAction
help_text = _("Add volume types to this group. "
"Multiple volume types can be added to the same "
"group only if they are associated with "
"same back end.")
available_list_title = _("All available volume types")
members_list_title = _("Selected volume types")
no_available_text = _("No volume types found.")
no_members_text = _("No volume types selected.")
show_roles = False
contributes = ("volume_types",)
def contribute(self, data, context):
if data:
member_field_name = self.get_member_field_name('member')
context['volume_types'] = data.get(member_field_name, [])
return context
class AddVolumesToGroupAction(workflows.MembershipAction):
def __init__(self, request, *args, **kwargs):
super(AddVolumesToGroupAction, self).__init__(request,
*args,
**kwargs)
err_msg = _('Unable to get the available volumes')
default_role_field_name = self.get_default_role_field_name()
self.fields[default_role_field_name] = forms.CharField(required=False)
self.fields[default_role_field_name].initial = 'member'
field_name = self.get_member_field_name('member')
self.fields[field_name] = forms.MultipleChoiceField(required=False)
vtypes = self.initial['vtypes']
try:
# get names of volume types associated with group
vtype_names = []
volume_types = cinder.volume_type_list(request)
for volume_type in volume_types:
if volume_type.id in vtypes:
vtype_names.append(volume_type.name)
# collect volumes that are associated with volume types
vol_list = []
volumes = cinder.volume_list(request)
for volume in volumes:
if volume.volume_type in vtype_names:
group_id = None
vol_is_available = False
in_this_group = False
if hasattr(volume, 'group_id'):
# this vol already belongs to a group
# only include it here if it belongs to this group
group_id = volume.group_id
if not group_id:
# put this vol in the available list
vol_is_available = True
elif group_id == self.initial['group_id']:
# put this vol in the assigned to group list
vol_is_available = True
in_this_group = True
if vol_is_available:
vol_list.append({'volume_name': volume.name,
'volume_id': volume.id,
'in_group': in_this_group,
'is_duplicate': False})
sorted_vol_list = sorted(vol_list, key=lambda k: k['volume_name'])
# mark any duplicate volume names
for index, volume in enumerate(sorted_vol_list):
if index < len(sorted_vol_list) - 1:
if volume['volume_name'] == \
sorted_vol_list[index + 1]['volume_name']:
volume['is_duplicate'] = True
sorted_vol_list[index + 1]['is_duplicate'] = True
# update display with all available vols and those already
# assigned to group
available_vols = []
assigned_vols = []
for volume in sorted_vol_list:
if volume['is_duplicate']:
# add id to differentiate volumes to user
entry = volume['volume_name'] + \
" [" + volume['volume_id'] + "]"
else:
entry = volume['volume_name']
available_vols.append((volume['volume_id'], entry))
if volume['in_group']:
assigned_vols.append(volume['volume_id'])
except Exception:
exceptions.handle(request, err_msg)
self.fields[field_name].choices = available_vols
self.fields[field_name].initial = assigned_vols
class Meta(object):
name = _("Manage Volumes")
slug = "add_volumes_to_group"
class AddVolumesToGroupStep(workflows.UpdateMembersStep):
action_class = AddVolumesToGroupAction
help_text = _("Add/remove volumes to/from this group. "
"Only volumes associated with the volume type(s) assigned "
"to this group will be available for selection.")
available_list_title = _("All available volumes")
members_list_title = _("Selected volumes")
no_available_text = _("No volumes found.")
no_members_text = _("No volumes selected.")
show_roles = False
depends_on = ("group_id", "name", "vtypes")
contributes = ("volumes",)
def contribute(self, data, context):
if data:
member_field_name = self.get_member_field_name('member')
context['volumes'] = data.get(member_field_name, [])
return context
class CreateGroupWorkflow(workflows.Workflow):
slug = "create_group"
name = _("Create Group")
finalize_button_name = _("Create Group")
failure_message = _('Unable to create group.')
success_message = _('Created new volume group')
success_url = INDEX_URL
default_steps = (AddGroupInfoStep,
AddVolTypesToGroupStep)
def handle(self, request, context):
try:
self.object = cinder.group_create(
request,
context['name'],
context['group_type'],
context['volume_types'],
description=context['description'],
availability_zone=context['availability_zone'])
except Exception:
exceptions.handle(request, _('Unable to create group.'))
return False
return True
class UpdateGroupWorkflow(workflows.Workflow):
slug = "update_group"
name = _("Add/Remove Group Volumes")
finalize_button_name = _("Submit")
success_message = _('Updated volumes for group.')
failure_message = _('Unable to update volumes for group')
success_url = INDEX_URL
default_steps = (AddVolumesToGroupStep,)
def handle(self, request, context):
group_id = context['group_id']
add_vols = []
remove_vols = []
try:
selected_volumes = context['volumes']
volumes = cinder.volume_list(request)
# scan all volumes and make correct consistency group is set
for volume in volumes:
selected = False
for selection in selected_volumes:
if selection == volume.id:
selected = True
break
if selected:
# ensure this volume is in this consistency group
if hasattr(volume, 'group_id'):
if volume.group_id != group_id:
add_vols.append(volume.id)
else:
add_vols.append(volume.id)
else:
# ensure this volume is not in our consistency group
if hasattr(volume, 'group_id'):
if volume.group_id == group_id:
# remove from this group
remove_vols.append(volume.id)
if not add_vols and not remove_vols:
# nothing to change
return True
cinder.group_update(request, group_id,
add_volumes=add_vols,
remove_volumes=remove_vols)
except Exception:
# error message supplied by form
return False
return True