Add volume group-type list/show support for admin panel
This commit allow admin to list/show cinder volume group-type using horizon dashboard and user can perform the following table action : 1. group-type-create 2. group-type-delete 3. group-type-update TODO: 1.group-type-specs support Partially-Implements blueprint cinder-generic-volume-groups Change-Id: Iea18913765cda146a0fcae7abe64c999a29cccfe
This commit is contained in:
@@ -1139,9 +1139,13 @@ def group_type_create(request, name, description=None, is_public=None):
|
|||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def group_type_update(request, group_type_id, data):
|
def group_type_update(request, group_type_id, name=None, description=None,
|
||||||
|
is_public=None):
|
||||||
client = _cinderclient_with_generic_groups(request)
|
client = _cinderclient_with_generic_groups(request)
|
||||||
return GroupType(client.group_types.update(group_type_id, **data))
|
return GroupType(client.group_types.update(group_type_id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
is_public))
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
|
107
openstack_dashboard/dashboards/admin/group_types/forms.py
Normal file
107
openstack_dashboard/dashboards/admin/group_types/forms.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
class CreateGroupType(forms.SelfHandlingForm):
|
||||||
|
name = forms.CharField(max_length=255, label=_("Name"))
|
||||||
|
group_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, group type is created as public. To "
|
||||||
|
"create a private group type, uncheck this field."))
|
||||||
|
|
||||||
|
def clean_name(self):
|
||||||
|
cleaned_name = self.cleaned_data['name']
|
||||||
|
if cleaned_name.isspace():
|
||||||
|
raise ValidationError(_('Group type name can not be empty.'))
|
||||||
|
|
||||||
|
return cleaned_name
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
group_type = cinder.group_type_create(
|
||||||
|
request,
|
||||||
|
data['name'],
|
||||||
|
data['group_type_description'],
|
||||||
|
data['is_public'])
|
||||||
|
messages.success(request, _('Successfully created group type: %s')
|
||||||
|
% data['name'])
|
||||||
|
return group_type
|
||||||
|
except Exception as e:
|
||||||
|
if getattr(e, 'code', None) == 409:
|
||||||
|
msg = _('Group type name "%s" already '
|
||||||
|
'exists.') % data['name']
|
||||||
|
self._errors['name'] = self.error_class([msg])
|
||||||
|
else:
|
||||||
|
redirect = reverse("horizon:admin:group_types:index")
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to create group type.'),
|
||||||
|
redirect=redirect)
|
||||||
|
|
||||||
|
|
||||||
|
class EditGroupType(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 group 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):
|
||||||
|
group_type_id = self.initial['id']
|
||||||
|
try:
|
||||||
|
cinder.group_type_update(request,
|
||||||
|
group_type_id,
|
||||||
|
data['name'],
|
||||||
|
data['description'],
|
||||||
|
data['is_public'])
|
||||||
|
message = _('Successfully updated group type.')
|
||||||
|
messages.success(request, message)
|
||||||
|
return True
|
||||||
|
except Exception as ex:
|
||||||
|
redirect = reverse("horizon:admin:group_types:index")
|
||||||
|
if ex.code == 409:
|
||||||
|
error_message = _('New name conflicts with another '
|
||||||
|
'group type.')
|
||||||
|
else:
|
||||||
|
error_message = _('Unable to update group type.')
|
||||||
|
|
||||||
|
exceptions.handle(request, error_message,
|
||||||
|
redirect=redirect)
|
24
openstack_dashboard/dashboards/admin/group_types/panel.py
Normal file
24
openstack_dashboard/dashboards/admin/group_types/panel.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 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 _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
|
||||||
|
class GroupTypes(horizon.Panel):
|
||||||
|
name = _("Group Types")
|
||||||
|
slug = 'group_types'
|
||||||
|
permissions = (
|
||||||
|
('openstack.services.volume', 'openstack.services.volumev3'),
|
||||||
|
)
|
||||||
|
policy_rules = (("volume", "group:group_types_manage"),)
|
124
openstack_dashboard/dashboards/admin/group_types/tables.py
Normal file
124
openstack_dashboard/dashboards/admin/group_types/tables.py
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# 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.template import defaultfilters as filters
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.translation import ungettext_lazy
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from openstack_dashboard.api import cinder
|
||||||
|
|
||||||
|
|
||||||
|
class CreateGroupType(tables.LinkAction):
|
||||||
|
name = "create"
|
||||||
|
verbose_name = _("Create Group Type")
|
||||||
|
url = "horizon:admin:group_types:create_type"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
policy_rules = (("volume", "group:group_types_manage"),)
|
||||||
|
|
||||||
|
|
||||||
|
class EditGroupType(tables.LinkAction):
|
||||||
|
name = "edit"
|
||||||
|
verbose_name = _("Edit Group Type")
|
||||||
|
url = "horizon:admin:group_types:update_type"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "pencil"
|
||||||
|
policy_rules = (("volume", "group:group_types_manage"),)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupTypesFilterAction(tables.FilterAction):
|
||||||
|
|
||||||
|
def filter(self, table, group_types, filter_string):
|
||||||
|
"""Naive case-insensitive search."""
|
||||||
|
query = filter_string.lower()
|
||||||
|
return [group_type for group_type in group_types
|
||||||
|
if query in group_type.name.lower()]
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteGroupType(tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Group Type",
|
||||||
|
u"Delete Group Types",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Group Type",
|
||||||
|
u"Deleted Group Types",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
policy_rules = (("volume", "group:group_types_manage"),)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
try:
|
||||||
|
cinder.group_type_delete(request, obj_id)
|
||||||
|
except exceptions.BadRequest as e:
|
||||||
|
redirect_url = reverse("horizon:admin:group_types:index")
|
||||||
|
exceptions.handle(request, e, redirect=redirect_url)
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateRow(tables.Row):
|
||||||
|
ajax = True
|
||||||
|
|
||||||
|
def get_data(self, request, group_type_id):
|
||||||
|
try:
|
||||||
|
group_type = \
|
||||||
|
cinder.group_type_get(request, group_type_id)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to retrieve group type.'))
|
||||||
|
return group_type
|
||||||
|
|
||||||
|
|
||||||
|
class GroupTypesTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn("name", verbose_name=_("Name"),
|
||||||
|
form_field=forms.CharField(max_length=64))
|
||||||
|
description = tables.Column(lambda obj: getattr(obj, 'description', None),
|
||||||
|
verbose_name=_('Description'),
|
||||||
|
form_field=forms.CharField(
|
||||||
|
widget=forms.Textarea(attrs={'rows': 4}),
|
||||||
|
required=False))
|
||||||
|
public = tables.Column("is_public",
|
||||||
|
verbose_name=_("Public"),
|
||||||
|
filters=(filters.yesno, filters.capfirst),
|
||||||
|
form_field=forms.BooleanField(
|
||||||
|
label=_('Public'), required=False))
|
||||||
|
|
||||||
|
def get_object_display(self, group_type):
|
||||||
|
return group_type.name
|
||||||
|
|
||||||
|
def get_object_id(self, group_type):
|
||||||
|
return str(group_type.id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "group_types"
|
||||||
|
verbose_name = _("Group Types")
|
||||||
|
table_actions = (
|
||||||
|
GroupTypesFilterAction,
|
||||||
|
CreateGroupType,
|
||||||
|
DeleteGroupType,
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
EditGroupType,
|
||||||
|
DeleteGroupType
|
||||||
|
)
|
||||||
|
row_class = UpdateRow
|
@@ -0,0 +1,16 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% blocktrans trimmed %}
|
||||||
|
Group type is a type or label that can be selected at group creation
|
||||||
|
time in OpenStack. It usually maps to a set of capabilities of the storage
|
||||||
|
back-end driver to be used for this volume. Examples: "Performance",
|
||||||
|
"SSD", "Backup", etc. This is equivalent to the
|
||||||
|
<tt>cinder type-create</tt> command. Once the group type gets created,
|
||||||
|
click the "Extra Specs" button to set up extra specs key-value
|
||||||
|
pair(s) for that group type.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_id %}{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:admin:group_types:update_type' group_type.id %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal_id %}update_group_type_modal{% endblock %}
|
||||||
|
{% block modal-header %}{% trans "Edit Group Type" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<div class="left">
|
||||||
|
<fieldset>
|
||||||
|
{% include "horizon/common/_form_fields.html" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Modify group type name, description, and public status." %}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Create Group Type" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'admin/group_types/_create_group_type.html' %}
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Edit Group Type" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Edit Group Type") %}
|
||||||
|
{% endblock page_header %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'admin/group_types/_update_group_type.html' %}
|
||||||
|
{% endblock %}
|
114
openstack_dashboard/dashboards/admin/group_types/tests.py
Normal file
114
openstack_dashboard/dashboards/admin/group_types/tests.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# 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.urls import reverse
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard.api import cinder
|
||||||
|
from openstack_dashboard.test import helpers as test
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:group_types:index')
|
||||||
|
|
||||||
|
|
||||||
|
class GroupTypeTests(test.BaseAdminViewTests):
|
||||||
|
@test.create_mocks({cinder: ('group_type_create',)})
|
||||||
|
def test_create_group_type(self):
|
||||||
|
group_type = self.cinder_group_types.first()
|
||||||
|
formData = {'name': 'group type 1',
|
||||||
|
'group_type_description': 'test desc',
|
||||||
|
'is_public': True}
|
||||||
|
|
||||||
|
self.mock_group_type_create.return_value = group_type
|
||||||
|
|
||||||
|
url = reverse('horizon:admin:group_types:create_type')
|
||||||
|
res = self.client.post(url, formData)
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
self.mock_group_type_create.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(),
|
||||||
|
formData['name'],
|
||||||
|
formData['group_type_description'],
|
||||||
|
formData['is_public'])
|
||||||
|
|
||||||
|
@test.create_mocks({api.cinder: ('group_type_get',
|
||||||
|
'group_type_update')})
|
||||||
|
def _test_update_group_type(self, is_public):
|
||||||
|
group_type = self.cinder_group_types.first()
|
||||||
|
formData = {'name': group_type.name,
|
||||||
|
'description': 'test desc updated',
|
||||||
|
'is_public': is_public}
|
||||||
|
self.mock_group_type_get.return_value = group_type
|
||||||
|
self.mock_group_type_update.return_value = group_type
|
||||||
|
|
||||||
|
url = reverse('horizon:admin:group_types:update_type',
|
||||||
|
args=[group_type.id])
|
||||||
|
res = self.client.post(url, formData)
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
self.mock_group_type_get.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), group_type.id)
|
||||||
|
self.mock_group_type_update.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(),
|
||||||
|
group_type.id,
|
||||||
|
formData['name'],
|
||||||
|
formData['description'],
|
||||||
|
formData['is_public'])
|
||||||
|
|
||||||
|
def test_update_group_type_public_true(self):
|
||||||
|
self._test_update_group_type(True)
|
||||||
|
|
||||||
|
def test_update_group_type_public_false(self):
|
||||||
|
self._test_update_group_type(False)
|
||||||
|
|
||||||
|
@test.create_mocks({api.cinder: ('group_type_list',
|
||||||
|
'group_type_delete',)})
|
||||||
|
def test_delete_group_type(self):
|
||||||
|
group_type = self.cinder_group_types.first()
|
||||||
|
formData = {'action': 'group_types__delete__%s' % group_type.id}
|
||||||
|
|
||||||
|
self.mock_group_type_list.return_value = \
|
||||||
|
self.cinder_group_types.list()
|
||||||
|
self.mock_group_type_delete.return_value = None
|
||||||
|
|
||||||
|
res = self.client.post(INDEX_URL, formData)
|
||||||
|
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
self.mock_group_type_list.\
|
||||||
|
assert_called_once_with(test.IsHttpRequest())
|
||||||
|
self.mock_group_type_delete.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), group_type.id)
|
||||||
|
|
||||||
|
@test.create_mocks({api.cinder: ('group_type_list',
|
||||||
|
'group_type_delete',)})
|
||||||
|
def test_delete_group_type_exception(self):
|
||||||
|
group_type = self.cinder_group_types.first()
|
||||||
|
formData = {'action': 'group_types__delete__%s' % group_type.id}
|
||||||
|
|
||||||
|
self.mock_group_type_list.return_value = \
|
||||||
|
self.cinder_group_types.list()
|
||||||
|
self.mock_group_type_delete.side_effect = exceptions.BadRequest()
|
||||||
|
|
||||||
|
res = self.client.post(INDEX_URL, formData)
|
||||||
|
|
||||||
|
self.assertNoFormErrors(res)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
self.mock_group_type_list.\
|
||||||
|
assert_called_once_with(test.IsHttpRequest())
|
||||||
|
self.mock_group_type_delete.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), group_type.id)
|
26
openstack_dashboard/dashboards/admin/group_types/urls.py
Normal file
26
openstack_dashboard/dashboards/admin/group_types/urls.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# 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.conf.urls import url
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.admin.group_types \
|
||||||
|
import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.GroupTypesView.as_view(), name='index'),
|
||||||
|
url(r'^create_type$', views.CreateGroupTypeView.as_view(),
|
||||||
|
name='create_type'),
|
||||||
|
url(r'^(?P<type_id>[^/]+)/update_type/$',
|
||||||
|
views.EditGroupTypeView.as_view(),
|
||||||
|
name='update_type'),
|
||||||
|
]
|
102
openstack_dashboard/dashboards/admin/group_types/views.py
Normal file
102
openstack_dashboard/dashboards/admin/group_types/views.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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.urls import reverse
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard.dashboards.admin.group_types \
|
||||||
|
import forms as group_types_forms
|
||||||
|
from openstack_dashboard.dashboards.admin.group_types \
|
||||||
|
import tables as group_types_tables
|
||||||
|
|
||||||
|
INDEX_URL = 'horizon:admin:group_types:index'
|
||||||
|
|
||||||
|
|
||||||
|
class GroupTypesView(tables.DataTableView):
|
||||||
|
table_class = group_types_tables.GroupTypesTable
|
||||||
|
page_title = _("Group Types")
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
group_types = api.cinder.group_type_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
group_types = []
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_("Unable to retrieve group types."))
|
||||||
|
|
||||||
|
return group_types
|
||||||
|
|
||||||
|
|
||||||
|
class CreateGroupTypeView(forms.ModalFormView):
|
||||||
|
form_class = group_types_forms.CreateGroupType
|
||||||
|
modal_id = "create_group_type_modal"
|
||||||
|
template_name = 'admin/group_types/create_group_type.html'
|
||||||
|
submit_label = _("Create Group Type")
|
||||||
|
submit_url = reverse_lazy("horizon:admin:group_types:create_type")
|
||||||
|
success_url = reverse_lazy('horizon:admin:group_types:index')
|
||||||
|
page_title = _("Create a Group Type")
|
||||||
|
|
||||||
|
|
||||||
|
class EditGroupTypeView(forms.ModalFormView):
|
||||||
|
form_class = group_types_forms.EditGroupType
|
||||||
|
template_name = 'admin/group_types/update_group_type.html'
|
||||||
|
success_url = reverse_lazy('horizon:admin:group_types:index')
|
||||||
|
cancel_url = reverse_lazy('horizon:admin:group_types:index')
|
||||||
|
submit_label = _('Edit')
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
group_type_id = self.kwargs['type_id']
|
||||||
|
group_type = api.cinder.group_type_get(self.request,
|
||||||
|
group_type_id)
|
||||||
|
except Exception:
|
||||||
|
error_message = _(
|
||||||
|
'Unable to retrieve group type for: "%s"') \
|
||||||
|
% group_type_id
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
error_message,
|
||||||
|
redirect=self.success_url)
|
||||||
|
|
||||||
|
return group_type
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(EditGroupTypeView, self).get_context_data(**kwargs)
|
||||||
|
context['group_type'] = self.get_data()
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
group_type = self.get_data()
|
||||||
|
return {'id': self.kwargs['type_id'],
|
||||||
|
'name': group_type.name,
|
||||||
|
'is_public': getattr(group_type, 'is_public', True),
|
||||||
|
'description': getattr(group_type, 'description', "")}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_group_type_name(request, kwargs):
|
||||||
|
try:
|
||||||
|
group_type_list = api.cinder.group_type_list(request)
|
||||||
|
for group_type in group_type_list:
|
||||||
|
if group_type.id == kwargs['group_type_id']:
|
||||||
|
return group_type.name
|
||||||
|
except Exception:
|
||||||
|
msg = _('Unable to retrieve group type name.')
|
||||||
|
url = reverse('INDEX_URL')
|
||||||
|
exceptions.handle(request, msg, redirect=url)
|
10
openstack_dashboard/enabled/_2270_admin_group_types_panel.py
Normal file
10
openstack_dashboard/enabled/_2270_admin_group_types_panel.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'group_types'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'volume'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = \
|
||||||
|
'openstack_dashboard.dashboards.admin.group_types.panel.GroupTypes'
|
Reference in New Issue
Block a user