Files
manila-ui/manila_ui/dashboards/project/share_groups/forms.py
Goutham Pacha Ravi 37e5b2f053 Fix parsing names in switched fields
In the share creation form dialog, share network
selection is optionally provided based on whether
the share type chosen supports the DHSS extra-spec.
This selection breaks often when dealing with share
types that have a name matching the format: ".*-\d+.*".
For example: test-700. The root cause of this seems to
be in javascript code for "switchable" fields [1] that
doesn't get triggered as expected.

A similar issue manifests in the share Network Creation
form where we setup switched fields with the Neutron
network IDs (dashed format UUIDs) and in the Share
Group Creation form where we setup switched fields
with the Share Group Type IDs (dashed format UUIDs).

So, we could encode the "-" in these field names to
workaround this issue.

Closes-Bug: #1931641
[1] 647c2b7530/horizon/static/horizon/js/horizon.forms.js (L491-L613)

Change-Id: Id924fc55debdc38ae2131bf8cef396f28caa3e77
Signed-off-by: Goutham Pacha Ravi <gouthampravi@gmail.com>
2021-06-16 12:14:17 -07:00

268 lines
11 KiB
Python

# Copyright 2017 Mirantis, Inc.
# All rights reserved.
#
# 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 horizon.utils import memoized
from manila_ui.api import manila
from manila_ui.dashboards import utils
class CreateShareGroupForm(forms.SelfHandlingForm):
name = forms.CharField(label=_("Name"), max_length="255", required=True)
description = forms.CharField(
label=_("Description"),
max_length="255",
widget=forms.Textarea(attrs={"rows": 3}),
required=False)
def __init__(self, request, *args, **kwargs):
super(CreateShareGroupForm, self).__init__(request, *args, **kwargs)
self.st_field_name_prefix = "share-type-choices-"
self.fields["source_type"] = forms.ChoiceField(
label=_("Source Type"),
widget=forms.Select(attrs={
"class": "switchable",
"data-slug": "source",
}),
required=False)
self.fields["snapshot"] = forms.ChoiceField(
label=_("Use share group snapshot as a source"),
widget=forms.SelectWidget(attrs={
"class": "switched",
"data-switch-on": "source",
"data-source-snapshot": _("Share Group Snapshot"),
}),
required=True)
if ("snapshot_id" in request.GET or
kwargs.get("data", {}).get("snapshot")):
try:
snapshot = self.get_share_group_snapshot(
request,
request.GET.get(
"snapshot_id",
kwargs.get("data", {}).get("snapshot")))
self.fields["name"].initial = snapshot.name
self.fields["snapshot"].choices = (
(snapshot.id, snapshot.name or snapshot.id),
)
try:
# Set the share group type from the original share group
orig_sg = manila.share_group_get(
request, snapshot.share_group_id)
self.fields["sgt"].initial = orig_sg.share_group_type_id
except Exception:
pass
del self.fields["source_type"]
except Exception:
exceptions.handle(
request,
_("Unable to load the specified share group snapshot."))
else:
source_type_choices = []
try:
snapshot_list = manila.share_group_snapshot_list(request)
snapshots = [s for s in snapshot_list
if s.status == "available"]
if snapshots:
source_type_choices.append(("snapshot", _("Snapshot")))
self.fields["snapshot"].choices = (
[("", _("Choose a snapshot"))] +
[(s.id, s.name or s.id) for s in snapshots]
)
else:
del self.fields["snapshot"]
except Exception:
exceptions.handle(
request,
_("Unable to retrieve share group snapshots."))
if source_type_choices:
choices = ([('none', _("No source, empty share group"))] +
source_type_choices)
self.fields["source_type"].choices = choices
else:
del self.fields["source_type"]
self.fields["az"] = forms.ChoiceField(
label=_("Availability Zone"),
widget=forms.SelectWidget(attrs={
"class": "switched",
"data-switch-on": "source",
"data-source-none": _("Availability Zone"),
}),
required=False)
availability_zones = manila.availability_zone_list(request)
self.fields["az"].choices = (
[("", "")] + [(az.name, az.name) for az in availability_zones])
share_group_types = manila.share_group_type_list(request)
self.fields["sgt"] = forms.ChoiceField(
label=_("Share Group Type"),
widget=forms.fields.SelectWidget(attrs={
"class": "switched switchable",
"data-switch-on": "source",
"data-source-none": _("Share Group Type"),
"data-slug": "sgt",
}),
required=True)
self.fields["sgt"].choices = (
[("", "")] + [(utils.transform_dashed_name(sgt.id), sgt.name)
for sgt in share_group_types]
)
# NOTE(vponomaryov): create separate set of available share types
# for each of share group types.
share_types = manila.share_type_list(request)
for sgt in share_group_types:
st_choices = (
[(st.id, st.name)
for st in share_types if st.id in sgt.share_types])
amount_of_choices = len(st_choices)
st_field_name = self.st_field_name_prefix + sgt.id
if amount_of_choices < 2:
st_field = forms.ChoiceField(
label=_("Share Types"),
choices=st_choices,
widget=forms.fields.SelectWidget(attrs={
"class": "switched",
"data-switch-on": "sgt",
"data-sgt-%s" % utils.transform_dashed_name(
sgt.id): _("Share Types (one available)"),
}),
required=True)
else:
height = min(30 * amount_of_choices, 155)
st_field = forms.MultipleChoiceField(
label=_("Share Types"),
choices=st_choices,
widget=forms.fields.widgets.SelectMultiple(attrs={
"style": "max-height: %spx;" % height,
"class": "switched",
"data-switch-on": "sgt",
"data-sgt-%s" % utils.transform_dashed_name(
sgt.id): _("Share Types (multiple available)"),
}),
required=False)
st_field.initial = st_choices[0]
self.fields[st_field_name] = st_field
self.fields["share_network"] = forms.ChoiceField(
label=_("Share Network"),
widget=forms.fields.SelectWidget(attrs={
"class": "switched",
"data-switch-on": "source",
"data-source-none": _("Share Network"),
}),
required=False)
share_networks = manila.share_network_list(request)
self.fields["share_network"].choices = (
[("", "")] +
[(sn.id, sn.name or sn.id) for sn in share_networks])
def clean(self):
cleaned_data = super(CreateShareGroupForm, self).clean()
form_errors = list(self.errors)
for error in form_errors:
sgt_name = error.split(self.st_field_name_prefix)[-1]
chosen_sgt = cleaned_data.get("sgt")
if (error.startswith(self.st_field_name_prefix) and
sgt_name != chosen_sgt):
cleaned_data[error] = "Not set"
self.errors.pop(error, None)
source_type = cleaned_data.get("source_type")
if source_type != "snapshot":
self.errors.pop("snapshot", None)
share_group_type = cleaned_data.get("sgt")
if share_group_type:
cleaned_data["share_types"] = cleaned_data.get(
self.st_field_name_prefix + share_group_type)
if isinstance(cleaned_data["share_types"], str):
cleaned_data["share_types"] = [cleaned_data["share_types"]]
else:
self.errors.pop("sgt", None)
return cleaned_data
def handle(self, request, data):
try:
source_type = data.get('source_type')
if (data.get("snapshot") and source_type in (None, 'snapshot')):
snapshot = self.get_share_group_snapshot(
request, data["snapshot"])
snapshot_id = snapshot.id
source_sg = manila.share_group_get(
request, snapshot.share_group_id)
data['sgt'] = source_sg.share_group_type_id
else:
snapshot_id = None
share_group = manila.share_group_create(
request,
name=data['name'],
description=data['description'],
share_group_type=utils.transform_dashed_name(data['sgt']),
share_types=None if snapshot_id else data.get('share_types'),
share_network=(
None if snapshot_id else data.get('share_network')),
source_share_group_snapshot=snapshot_id,
availability_zone=None if snapshot_id else data['az'])
message = _('Creating share group "%s"') % data['name']
messages.success(request, message)
return share_group
except ValidationError as e:
self.api_error(e.messages[0])
return False
except Exception:
exceptions.handle(request, ignore=True)
self.api_error(_("Unable to create share group."))
return False
@memoized.memoized
def get_share_group_snapshot(self, request, sg_snapshot_id):
return manila.share_group_snapshot_get(request, sg_snapshot_id)
class UpdateShareGroupForm(forms.SelfHandlingForm):
name = forms.CharField(
max_length="255", label=_("Share Group Name"))
description = forms.CharField(
widget=forms.Textarea, label=_("Description"), required=False)
def handle(self, request, data):
sg_id = self.initial['share_group_id']
try:
manila.share_group_update(
request, sg_id, data['name'], data['description'])
message = _('Updating share group "%s"') % data['name']
messages.success(request, message)
return True
except Exception:
redirect = reverse("horizon:project:share_groups:index")
exceptions.handle(
request, _('Unable to update share group.'), redirect=redirect)
return False