Refactor Volumes from tabbed panel to stand-alone
This edit unfortunately contains more changes than the others because it effectively merges a bunch of files under admin/volumes/*.py Change-Id: I52f3444a92fc83982a95760673419b4b4d746ad3 Implements: blueprint reorganise-volumes
This commit is contained in:
parent
0e0172ef38
commit
e0b6936178
@ -115,7 +115,7 @@ class UpdateStatusView(forms.ModalFormView):
|
||||
|
||||
class DetailView(views.DetailView):
|
||||
tab_group_class = vol_snapshot_tabs.SnapshotDetailsTabs
|
||||
volume_url = 'horizon:admin:volumes:volumes:detail'
|
||||
volume_url = 'horizon:admin:volumes:detail'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
|
@ -210,7 +210,7 @@ class MigrateVolume(forms.SelfHandlingForm):
|
||||
% data['name'])
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:volumes:volumes_tab")
|
||||
redirect = reverse("horizon:admin:volumes:index")
|
||||
exceptions.handle(request, _("Failed to migrate volume."),
|
||||
redirect=redirect)
|
||||
|
@ -37,7 +37,7 @@ class VolumesFilterAction(tables.FilterAction):
|
||||
class ManageVolumeAction(tables.LinkAction):
|
||||
name = "manage"
|
||||
verbose_name = _("Manage Volume")
|
||||
url = "horizon:admin:volumes:volumes:manage"
|
||||
url = "horizon:admin:volumes:manage"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
policy_rules = (("volume", "volume_extension:volume_manage"),)
|
||||
@ -47,7 +47,7 @@ class ManageVolumeAction(tables.LinkAction):
|
||||
class UnmanageVolumeAction(tables.LinkAction):
|
||||
name = "unmanage"
|
||||
verbose_name = _("Unmanage Volume")
|
||||
url = "horizon:admin:volumes:volumes:unmanage"
|
||||
url = "horizon:admin:volumes:unmanage"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("volume", "volume_extension:volume_unmanage"),)
|
||||
@ -73,7 +73,7 @@ class UnmanageVolumeAction(tables.LinkAction):
|
||||
class MigrateVolume(tables.LinkAction):
|
||||
name = "migrate"
|
||||
verbose_name = _("Migrate Volume")
|
||||
url = "horizon:admin:volumes:volumes:migrate"
|
||||
url = "horizon:admin:volumes:migrate"
|
||||
classes = ("ajax-modal", "btn-migrate")
|
||||
policy_rules = (
|
||||
("volume", "volume_extension:volume_admin_actions:migrate_volume"),)
|
||||
@ -85,7 +85,7 @@ class MigrateVolume(tables.LinkAction):
|
||||
class UpdateVolumeStatusAction(tables.LinkAction):
|
||||
name = "update_status"
|
||||
verbose_name = _("Update Volume Status")
|
||||
url = "horizon:admin:volumes:volumes:update_status"
|
||||
url = "horizon:admin:volumes:update_status"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("volume",
|
||||
@ -95,7 +95,7 @@ class UpdateVolumeStatusAction(tables.LinkAction):
|
||||
class VolumesTable(volumes_tables.VolumesTable):
|
||||
name = tables.WrappingColumn("name",
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:admin:volumes:volumes:detail")
|
||||
link="horizon:admin:volumes:detail")
|
||||
host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
|
||||
tenant = tables.Column(lambda obj: getattr(obj, 'tenant_name', None),
|
||||
verbose_name=_("Project"))
|
@ -1,104 +0,0 @@
|
||||
# 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 collections import OrderedDict
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
|
||||
from openstack_dashboard.api import keystone
|
||||
|
||||
from openstack_dashboard.dashboards.admin.volumes.volumes \
|
||||
import tables as volumes_tables
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
import views as volumes_views
|
||||
|
||||
|
||||
class VolumeTab(tables.PagedTableMixin, tabs.TableTab,
|
||||
volumes_views.VolumeTableMixIn, tables.DataTableView):
|
||||
table_classes = (volumes_tables.VolumesTable,)
|
||||
name = _("Volumes")
|
||||
slug = "volumes_tab"
|
||||
template_name = "admin/volumes/volumes/volumes_tables.html"
|
||||
preload = False
|
||||
FILTERS_MAPPING = {'bootable': {_('yes'): 'true', _('no'): 'false'},
|
||||
'encrypted': {_('yes'): True, _('no'): False}}
|
||||
|
||||
def get_volumes_data(self):
|
||||
default_filters = {'all_tenants': True}
|
||||
|
||||
filters = self.get_filters(default_filters.copy())
|
||||
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||
volumes = []
|
||||
|
||||
self.table.needs_filter_first = False
|
||||
|
||||
if filter_first.get('admin.volumes', False) and \
|
||||
len(filters) == len(default_filters):
|
||||
self.table.needs_filter_first = True
|
||||
return volumes
|
||||
|
||||
if 'project' in filters:
|
||||
# Keystone returns a tuple ([],false) where the first element is
|
||||
# tenant list that's why the 0 is hardcoded below
|
||||
tenants = keystone.tenant_list(self.request)[0]
|
||||
tenant_ids = [t.id for t in tenants
|
||||
if t.name == filters['project']]
|
||||
if not tenant_ids:
|
||||
return []
|
||||
del filters['project']
|
||||
for id in tenant_ids:
|
||||
filters['project_id'] = id
|
||||
volumes += self._get_volumes(search_opts=filters)
|
||||
else:
|
||||
volumes = self._get_volumes(search_opts=filters)
|
||||
|
||||
attached_instance_ids = self._get_attached_instance_ids(volumes)
|
||||
instances = self._get_instances(search_opts={'all_tenants': True},
|
||||
instance_ids=attached_instance_ids)
|
||||
volume_ids_with_snapshots = self._get_volumes_ids_with_snapshots(
|
||||
search_opts={'all_tenants': True})
|
||||
self._set_volume_attributes(
|
||||
volumes, instances, volume_ids_with_snapshots)
|
||||
|
||||
# Gather our tenants to correlate against IDs
|
||||
try:
|
||||
tenants, has_more = keystone.tenant_list(self.request)
|
||||
except Exception:
|
||||
tenants = []
|
||||
msg = _('Unable to retrieve volume project information.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
tenant_dict = OrderedDict([(t.id, t) for t in tenants])
|
||||
for volume in volumes:
|
||||
tenant_id = getattr(volume, "os-vol-tenant-attr:tenant_id", None)
|
||||
tenant = tenant_dict.get(tenant_id, None)
|
||||
volume.tenant_name = getattr(tenant, "name", None)
|
||||
|
||||
return volumes
|
||||
|
||||
def get_filters(self, filters):
|
||||
self.table = self._tables['volumes']
|
||||
self.handle_server_filter(self.request, table=self.table)
|
||||
self.update_server_filter_action(self.request, table=self.table)
|
||||
filters = super(VolumeTab, self).get_filters(filters,
|
||||
self.FILTERS_MAPPING)
|
||||
return filters
|
||||
|
||||
|
||||
class VolumesGroupTabs(tabs.TabGroup):
|
||||
slug = "volumes_group_tabs"
|
||||
tabs = (VolumeTab, )
|
||||
sticky = True
|
@ -1,11 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Volumes" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -28,6 +28,8 @@ from openstack_dashboard.dashboards.project.volumes \
|
||||
import tables as volume_tables
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
from openstack_dashboard.dashboards.admin.snapshots import forms
|
||||
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:volumes:index')
|
||||
|
||||
@ -72,7 +74,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/volumes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_data_table_view.html')
|
||||
volumes = res.context['volumes_table'].data
|
||||
self.assertItemsEqual(volumes, self.cinder_volumes.list())
|
||||
|
||||
@ -108,7 +110,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
|
||||
res = self.client.get(urlunquote(url))
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/volumes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_data_table_view.html')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
self.mox.UnsetStubs()
|
||||
@ -117,7 +119,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
@override_settings(FILTER_DATA_FIRST={'admin.volumes': True})
|
||||
def test_volumes_tab_with_admin_filter_first(self):
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'admin/volumes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_data_table_view.html')
|
||||
volumes = res.context['volumes_table'].data
|
||||
self.assertItemsEqual(volumes, [])
|
||||
|
||||
@ -147,7 +149,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
expected_volumes = mox_volumes[size:2 * size]
|
||||
marker = expected_volumes[0].id
|
||||
next = volume_tables.VolumesTable._meta.pagination_param
|
||||
url = "?".join([INDEX_URL, "=".join([next, marker])])
|
||||
url = INDEX_URL + "?%s=%s" % (next, marker)
|
||||
res = self._test_index_paginated(marker=marker, sort_dir="desc",
|
||||
volumes=expected_volumes, url=url,
|
||||
has_more=True, has_prev=True)
|
||||
@ -158,7 +160,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
expected_volumes = mox_volumes[-size:]
|
||||
marker = expected_volumes[0].id
|
||||
next = volume_tables.VolumesTable._meta.pagination_param
|
||||
url = "?".join([INDEX_URL, "=".join([next, marker])])
|
||||
url = INDEX_URL + "?%s=%s" % (next, marker)
|
||||
res = self._test_index_paginated(marker=marker, sort_dir="desc",
|
||||
volumes=expected_volumes, url=url,
|
||||
has_more=False, has_prev=True)
|
||||
@ -174,7 +176,7 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
expected_volumes = mox_volumes[size:2 * size]
|
||||
marker = mox_volumes[0].id
|
||||
prev = volume_tables.VolumesTable._meta.prev_pagination_param
|
||||
url = "?".join([INDEX_URL, "=".join([prev, marker])])
|
||||
url = INDEX_URL + "?%s=%s" % (prev, marker)
|
||||
res = self._test_index_paginated(marker=marker, sort_dir="asc",
|
||||
volumes=expected_volumes, url=url,
|
||||
has_more=False, has_prev=True)
|
||||
@ -185,9 +187,210 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
expected_volumes = mox_volumes[:size]
|
||||
marker = mox_volumes[0].id
|
||||
prev = volume_tables.VolumesTable._meta.prev_pagination_param
|
||||
url = "?".join([INDEX_URL, "=".join([prev, marker])])
|
||||
url = INDEX_URL + "?%s=%s" % (prev, marker)
|
||||
res = self._test_index_paginated(marker=marker, sort_dir="asc",
|
||||
volumes=expected_volumes, url=url,
|
||||
has_more=True, has_prev=False)
|
||||
volumes = res.context['volumes_table'].data
|
||||
self.assertItemsEqual(volumes, expected_volumes)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_reset_state',
|
||||
'volume_get')})
|
||||
def test_update_volume_status(self):
|
||||
volume = self.volumes.first()
|
||||
formData = {'status': 'error'}
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
|
||||
cinder.volume_reset_state(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
formData['status'])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:update_status',
|
||||
args=(volume.id,)),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_manage',
|
||||
'volume_type_list',
|
||||
'availability_zone_list',
|
||||
'extension_supported')})
|
||||
def test_manage_volume(self):
|
||||
metadata = {'key': u'k1',
|
||||
'value': u'v1'}
|
||||
formData = {'host': 'host-1',
|
||||
'identifier': 'vol-1',
|
||||
'id_type': u'source-name',
|
||||
'name': 'name-1',
|
||||
'description': 'manage a volume',
|
||||
'volume_type': 'vol_type_1',
|
||||
'availability_zone': 'nova',
|
||||
'metadata': metadata['key'] + '=' + metadata['value'],
|
||||
'bootable': False}
|
||||
cinder.volume_type_list(
|
||||
IsA(http.HttpRequest)). \
|
||||
AndReturn(self.cinder_volume_types.list())
|
||||
cinder.availability_zone_list(
|
||||
IsA(http.HttpRequest)). \
|
||||
AndReturn(self.availability_zones.list())
|
||||
cinder.extension_supported(
|
||||
IsA(http.HttpRequest),
|
||||
'AvailabilityZones'). \
|
||||
AndReturn(True)
|
||||
cinder.volume_manage(
|
||||
IsA(http.HttpRequest),
|
||||
host=formData['host'],
|
||||
identifier=formData['identifier'],
|
||||
id_type=formData['id_type'],
|
||||
name=formData['name'],
|
||||
description=formData['description'],
|
||||
volume_type=formData['volume_type'],
|
||||
availability_zone=formData['availability_zone'],
|
||||
metadata={metadata['key']: metadata['value']},
|
||||
bootable=formData['bootable'])
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:manage'),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_unmanage',
|
||||
'volume_get')})
|
||||
def test_unmanage_volume(self):
|
||||
# important - need to get the v2 cinder volume which has host data
|
||||
volume_list = [x for x in self.cinder_volumes.list()
|
||||
if x.name == 'v2_volume']
|
||||
volume = volume_list[0]
|
||||
formData = {'volume_name': volume.name,
|
||||
'host_name': 'host@backend-name#pool',
|
||||
'volume_id': volume.id}
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
|
||||
cinder.volume_unmanage(IsA(http.HttpRequest), volume.id). \
|
||||
AndReturn(volume)
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:unmanage',
|
||||
args=(volume.id,)),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',)})
|
||||
def test_volume_migrate_get(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'admin/volumes/migrate_volume.html')
|
||||
|
||||
@test.create_stubs({cinder: ('volume_get',)})
|
||||
def test_volume_migrate_get_volume_get_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',)})
|
||||
def test_volume_migrate_list_pool_get_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
url = reverse('horizon:admin:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',
|
||||
'volume_migrate',)})
|
||||
def test_volume_migrate_post(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
host = self.cinder_pools.first().name
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
cinder.volume_migrate(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
host,
|
||||
False) \
|
||||
.AndReturn(None)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.post(url, {'host': host, 'volume_id': volume.id})
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',
|
||||
'volume_migrate',)})
|
||||
def test_volume_migrate_post_api_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
host = self.cinder_pools.first().name
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
cinder.volume_migrate(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
host,
|
||||
False) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.post(url, {'host': host, 'volume_id': volume.id})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_get_volume_status_choices_without_current(self):
|
||||
current_status = {'status': 'available'}
|
||||
status_choices = forms.populate_status_choices(current_status,
|
||||
forms.STATUS_CHOICES)
|
||||
self.assertEqual(len(status_choices), len(forms.STATUS_CHOICES))
|
||||
self.assertNotIn(current_status['status'],
|
||||
[status[0] for status in status_choices])
|
||||
|
||||
@test.create_stubs({cinder: ('volume_get',)})
|
||||
def test_update_volume_status_get(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:update_status',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
status_option = "<option value=\"%s\"></option>" % volume.status
|
||||
self.assertNotContains(res, status_option)
|
||||
|
@ -10,20 +10,28 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.conf.urls import include
|
||||
from django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.admin.volumes import views
|
||||
from openstack_dashboard.dashboards.admin.volumes.volumes \
|
||||
import urls as volumes_urls
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$',
|
||||
views.IndexView.as_view(),
|
||||
views.VolumesView.as_view(),
|
||||
name='index'),
|
||||
url(r'^\?tab=volumes_group_tabs__volumes_tab$',
|
||||
views.IndexView.as_view(),
|
||||
name='volumes_tab'),
|
||||
url(r'',
|
||||
include(volumes_urls, namespace='volumes')),
|
||||
url(r'^manage/$',
|
||||
views.ManageVolumeView.as_view(),
|
||||
name='manage'),
|
||||
url(r'^(?P<volume_id>[^/]+)/$',
|
||||
views.DetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'^(?P<volume_id>[^/]+)/update_status$',
|
||||
views.UpdateStatusView.as_view(),
|
||||
name='update_status'),
|
||||
url(r'^(?P<volume_id>[^/]+)/unmanage$',
|
||||
views.UnmanageVolumeView.as_view(),
|
||||
name='unmanage'),
|
||||
url(r'^(?P<volume_id>[^/]+)/migrate$',
|
||||
views.MigrateVolumeView.as_view(),
|
||||
name='migrate'),
|
||||
]
|
||||
|
@ -15,15 +15,229 @@
|
||||
"""
|
||||
Admin views for managing volumes and snapshots.
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tabs
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard.api import cinder
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.dashboards.admin.volumes \
|
||||
import tabs as volumes_tabs
|
||||
import forms as volumes_forms
|
||||
from openstack_dashboard.dashboards.admin.volumes \
|
||||
import tables as volumes_tables
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
import views as volumes_views
|
||||
|
||||
|
||||
class IndexView(tabs.TabbedTableView):
|
||||
tab_group_class = volumes_tabs.VolumesGroupTabs
|
||||
template_name = 'admin/volumes/index.html'
|
||||
class VolumesView(tables.PagedTableMixin, volumes_views.VolumeTableMixIn,
|
||||
tables.DataTableView):
|
||||
table_class = volumes_tables.VolumesTable
|
||||
page_title = _("Volumes")
|
||||
|
||||
FILTERS_MAPPING = {'bootable': {_('yes'): 'true', _('no'): 'false'},
|
||||
'encrypted': {_('yes'): True, _('no'): False}}
|
||||
|
||||
def get_data(self):
|
||||
default_filters = {'all_tenants': True}
|
||||
|
||||
filters = self.get_filters(default_filters.copy())
|
||||
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||
volumes = []
|
||||
|
||||
self.table.needs_filter_first = False
|
||||
|
||||
if filter_first.get('admin.volumes', False) and \
|
||||
len(filters) == len(default_filters):
|
||||
self.table.needs_filter_first = True
|
||||
return volumes
|
||||
|
||||
if 'project' in filters:
|
||||
# Keystone returns a tuple ([],false) where the first element is
|
||||
# tenant list that's why the 0 is hardcoded below
|
||||
tenants = keystone.tenant_list(self.request)[0]
|
||||
tenant_ids = [t.id for t in tenants
|
||||
if t.name == filters['project']]
|
||||
if not tenant_ids:
|
||||
return []
|
||||
del filters['project']
|
||||
for id in tenant_ids:
|
||||
filters['project_id'] = id
|
||||
volumes += self._get_volumes(search_opts=filters)
|
||||
else:
|
||||
volumes = self._get_volumes(search_opts=filters)
|
||||
|
||||
attached_instance_ids = self._get_attached_instance_ids(volumes)
|
||||
instances = self._get_instances(search_opts={'all_tenants': True},
|
||||
instance_ids=attached_instance_ids)
|
||||
volume_ids_with_snapshots = self._get_volumes_ids_with_snapshots(
|
||||
search_opts={'all_tenants': True})
|
||||
self._set_volume_attributes(
|
||||
volumes, instances, volume_ids_with_snapshots)
|
||||
|
||||
# Gather our tenants to correlate against IDs
|
||||
try:
|
||||
tenants, has_more = keystone.tenant_list(self.request)
|
||||
except Exception:
|
||||
tenants = []
|
||||
msg = _('Unable to retrieve volume project information.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
tenant_dict = OrderedDict([(t.id, t) for t in tenants])
|
||||
for volume in volumes:
|
||||
tenant_id = getattr(volume, "os-vol-tenant-attr:tenant_id", None)
|
||||
tenant = tenant_dict.get(tenant_id, None)
|
||||
volume.tenant_name = getattr(tenant, "name", None)
|
||||
|
||||
return volumes
|
||||
|
||||
def get_filters(self, filters):
|
||||
self.table = self._tables['volumes']
|
||||
self.handle_server_filter(self.request, table=self.table)
|
||||
self.update_server_filter_action(self.request, table=self.table)
|
||||
filters = super(VolumesView, self).get_filters(filters,
|
||||
self.FILTERS_MAPPING)
|
||||
return filters
|
||||
|
||||
|
||||
class DetailView(volumes_views.DetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
table = volumes_tables.VolumesTable(self.request)
|
||||
context["actions"] = table.render_row_actions(context["volume"])
|
||||
return context
|
||||
|
||||
def get_redirect_url(self):
|
||||
return reverse('horizon:admin:volumes:index')
|
||||
|
||||
|
||||
class ManageVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.ManageVolume
|
||||
template_name = 'admin/volumes/manage_volume.html'
|
||||
form_id = "manage_volume_modal"
|
||||
submit_label = _("Manage")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
submit_url = reverse_lazy('horizon:admin:volumes:manage')
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Manage Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ManageVolumeView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
|
||||
class UnmanageVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.UnmanageVolume
|
||||
template_name = 'admin/volumes/unmanage_volume.html'
|
||||
form_id = "unmanage_volume_modal"
|
||||
submit_label = _("Unmanage")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
submit_url = 'horizon:admin:volumes:unmanage'
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Unmanage Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UnmanageVolumeView, self).get_context_data(**kwargs)
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'name': volume.name,
|
||||
'host': getattr(volume, "os-vol-host-attr:host")}
|
||||
|
||||
|
||||
class MigrateVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.MigrateVolume
|
||||
template_name = 'admin/volumes/migrate_volume.html'
|
||||
form_id = "migrate_volume_modal"
|
||||
submit_label = _("Migrate")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
submit_url = 'horizon:admin:volumes:migrate'
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Migrate Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MigrateVolumeView, self).get_context_data(**kwargs)
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_hosts(self):
|
||||
try:
|
||||
return cinder.pool_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve pools information.'),
|
||||
redirect=self.success_url)
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'name': volume.name,
|
||||
'current_host': getattr(volume, "os-vol-host-attr:host"),
|
||||
'hosts': self.get_hosts()}
|
||||
|
||||
|
||||
class UpdateStatusView(forms.ModalFormView):
|
||||
form_class = volumes_forms.UpdateStatus
|
||||
modal_id = "update_volume_status_modal"
|
||||
template_name = 'admin/volumes/update_status.html'
|
||||
submit_label = _("Update Status")
|
||||
submit_url = "horizon:admin:volumes:update_status"
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
page_title = _("Update Volume Status")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateStatusView, self).get_context_data(**kwargs)
|
||||
context["volume_id"] = self.kwargs['volume_id']
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'status': volume.status}
|
||||
|
@ -1,235 +0,0 @@
|
||||
#
|
||||
# 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.core.urlresolvers import reverse
|
||||
from django import http
|
||||
from mox3.mox import IsA # noqa
|
||||
|
||||
from openstack_dashboard.api import cinder
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
from openstack_dashboard.dashboards.admin.snapshots import forms
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:volumes:volumes_tab')
|
||||
|
||||
|
||||
class VolumeViewTests(test.BaseAdminViewTests):
|
||||
def tearDown(self):
|
||||
for volume in self.cinder_volumes.list():
|
||||
# VolumeTableMixIn._set_volume_attributes mutates data
|
||||
# and cinder_volumes.list() doesn't deep copy
|
||||
for att in volume.attachments:
|
||||
if 'instance' in att:
|
||||
del att['instance']
|
||||
super(VolumeViewTests, self).tearDown()
|
||||
|
||||
@test.create_stubs({cinder: ('volume_reset_state',
|
||||
'volume_get')})
|
||||
def test_update_volume_status(self):
|
||||
volume = self.volumes.first()
|
||||
formData = {'status': 'error'}
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
|
||||
cinder.volume_reset_state(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
formData['status'])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:volumes:update_status',
|
||||
args=(volume.id,)),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_manage',
|
||||
'volume_type_list',
|
||||
'availability_zone_list',
|
||||
'extension_supported')})
|
||||
def test_manage_volume(self):
|
||||
metadata = {'key': u'k1',
|
||||
'value': u'v1'}
|
||||
formData = {'host': 'host-1',
|
||||
'identifier': 'vol-1',
|
||||
'id_type': u'source-name',
|
||||
'name': 'name-1',
|
||||
'description': 'manage a volume',
|
||||
'volume_type': 'vol_type_1',
|
||||
'availability_zone': 'nova',
|
||||
'metadata': metadata['key'] + '=' + metadata['value'],
|
||||
'bootable': False}
|
||||
cinder.volume_type_list(
|
||||
IsA(http.HttpRequest)).\
|
||||
AndReturn(self.cinder_volume_types.list())
|
||||
cinder.availability_zone_list(
|
||||
IsA(http.HttpRequest)).\
|
||||
AndReturn(self.availability_zones.list())
|
||||
cinder.extension_supported(
|
||||
IsA(http.HttpRequest),
|
||||
'AvailabilityZones').\
|
||||
AndReturn(True)
|
||||
cinder.volume_manage(
|
||||
IsA(http.HttpRequest),
|
||||
host=formData['host'],
|
||||
identifier=formData['identifier'],
|
||||
id_type=formData['id_type'],
|
||||
name=formData['name'],
|
||||
description=formData['description'],
|
||||
volume_type=formData['volume_type'],
|
||||
availability_zone=formData['availability_zone'],
|
||||
metadata={metadata['key']: metadata['value']},
|
||||
bootable=formData['bootable'])
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:volumes:manage'),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('volume_unmanage',
|
||||
'volume_get')})
|
||||
def test_unmanage_volume(self):
|
||||
# important - need to get the v2 cinder volume which has host data
|
||||
volume_list = [x for x in self.cinder_volumes.list()
|
||||
if x.name == 'v2_volume']
|
||||
volume = volume_list[0]
|
||||
formData = {'volume_name': volume.name,
|
||||
'host_name': 'host@backend-name#pool',
|
||||
'volume_id': volume.id}
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
|
||||
cinder.volume_unmanage(IsA(http.HttpRequest), volume.id).\
|
||||
AndReturn(volume)
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.post(
|
||||
reverse('horizon:admin:volumes:volumes:unmanage',
|
||||
args=(volume.id,)),
|
||||
formData)
|
||||
self.assertNoFormErrors(res)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',)})
|
||||
def test_volume_migrate_get(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res,
|
||||
'admin/volumes/volumes/migrate_volume.html')
|
||||
|
||||
@test.create_stubs({cinder: ('volume_get',)})
|
||||
def test_volume_migrate_get_volume_get_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',)})
|
||||
def test_volume_migrate_list_pool_get_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
url = reverse('horizon:admin:volumes:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',
|
||||
'volume_migrate',)})
|
||||
def test_volume_migrate_post(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
host = self.cinder_pools.first().name
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
cinder.volume_migrate(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
host,
|
||||
False) \
|
||||
.AndReturn(None)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.post(url, {'host': host, 'volume_id': volume.id})
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({cinder: ('pool_list',
|
||||
'volume_get',
|
||||
'volume_migrate',)})
|
||||
def test_volume_migrate_post_api_exception(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
host = self.cinder_pools.first().name
|
||||
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
cinder.pool_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.cinder_pools.list())
|
||||
cinder.volume_migrate(IsA(http.HttpRequest),
|
||||
volume.id,
|
||||
host,
|
||||
False) \
|
||||
.AndRaise(self.exceptions.cinder)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:volumes:migrate',
|
||||
args=[volume.id])
|
||||
res = self.client.post(url, {'host': host, 'volume_id': volume.id})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_get_volume_status_choices_without_current(self):
|
||||
current_status = {'status': 'available'}
|
||||
status_choices = forms.populate_status_choices(current_status,
|
||||
forms.STATUS_CHOICES)
|
||||
self.assertEqual(len(status_choices), len(forms.STATUS_CHOICES))
|
||||
self.assertNotIn(current_status['status'],
|
||||
[status[0] for status in status_choices])
|
||||
|
||||
@test.create_stubs({cinder: ('volume_get',)})
|
||||
def test_update_volume_status_get(self):
|
||||
volume = self.cinder_volumes.get(name='v2_volume')
|
||||
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
|
||||
.AndReturn(volume)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:volumes:volumes:update_status',
|
||||
args=[volume.id])
|
||||
res = self.client.get(url)
|
||||
status_option = "<option value=\"%s\"></option>" % volume.status
|
||||
self.assertNotContains(res, status_option)
|
@ -1,34 +0,0 @@
|
||||
# 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.volumes.volumes \
|
||||
import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^manage/$',
|
||||
views.ManageVolumeView.as_view(),
|
||||
name='manage'),
|
||||
url(r'^(?P<volume_id>[^/]+)/$',
|
||||
views.DetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'^(?P<volume_id>[^/]+)/update_status$',
|
||||
views.UpdateStatusView.as_view(),
|
||||
name='update_status'),
|
||||
url(r'^(?P<volume_id>[^/]+)/unmanage$',
|
||||
views.UnmanageVolumeView.as_view(),
|
||||
name='unmanage'),
|
||||
url(r'^(?P<volume_id>[^/]+)/migrate$',
|
||||
views.MigrateVolumeView.as_view(),
|
||||
name='migrate'),
|
||||
]
|
@ -1,164 +0,0 @@
|
||||
# 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.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard.api import cinder
|
||||
from openstack_dashboard.dashboards.admin.volumes.volumes \
|
||||
import forms as volumes_forms
|
||||
from openstack_dashboard.dashboards.admin.volumes.volumes \
|
||||
import tables as volumes_tables
|
||||
from openstack_dashboard.dashboards.project.volumes \
|
||||
import views as volumes_views
|
||||
|
||||
|
||||
class DetailView(volumes_views.DetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
table = volumes_tables.VolumesTable(self.request)
|
||||
context["actions"] = table.render_row_actions(context["volume"])
|
||||
return context
|
||||
|
||||
def get_redirect_url(self):
|
||||
return reverse('horizon:admin:volumes:index')
|
||||
|
||||
|
||||
class ManageVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.ManageVolume
|
||||
template_name = 'admin/volumes/volumes/manage_volume.html'
|
||||
form_id = "manage_volume_modal"
|
||||
submit_label = _("Manage")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:volumes_tab')
|
||||
submit_url = reverse_lazy('horizon:admin:volumes:volumes:manage')
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Manage Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ManageVolumeView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
|
||||
class UnmanageVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.UnmanageVolume
|
||||
template_name = 'admin/volumes/volumes/unmanage_volume.html'
|
||||
form_id = "unmanage_volume_modal"
|
||||
submit_label = _("Unmanage")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:volumes_tab')
|
||||
submit_url = 'horizon:admin:volumes:volumes:unmanage'
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Unmanage Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UnmanageVolumeView, self).get_context_data(**kwargs)
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'name': volume.name,
|
||||
'host': getattr(volume, "os-vol-host-attr:host")}
|
||||
|
||||
|
||||
class MigrateVolumeView(forms.ModalFormView):
|
||||
form_class = volumes_forms.MigrateVolume
|
||||
template_name = 'admin/volumes/volumes/migrate_volume.html'
|
||||
form_id = "migrate_volume_modal"
|
||||
submit_label = _("Migrate")
|
||||
success_url = reverse_lazy('horizon:admin:volumes:volumes_tab')
|
||||
submit_url = 'horizon:admin:volumes:volumes:migrate'
|
||||
cancel_url = reverse_lazy("horizon:admin:volumes:index")
|
||||
page_title = _("Migrate Volume")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MigrateVolumeView, self).get_context_data(**kwargs)
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_hosts(self):
|
||||
try:
|
||||
return cinder.pool_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve pools information.'),
|
||||
redirect=self.success_url)
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'name': volume.name,
|
||||
'current_host': getattr(volume, "os-vol-host-attr:host"),
|
||||
'hosts': self.get_hosts()}
|
||||
|
||||
|
||||
class UpdateStatusView(forms.ModalFormView):
|
||||
form_class = volumes_forms.UpdateStatus
|
||||
modal_id = "update_volume_status_modal"
|
||||
template_name = 'admin/volumes/volumes/update_status.html'
|
||||
submit_label = _("Update Status")
|
||||
submit_url = "horizon:admin:volumes:volumes:update_status"
|
||||
success_url = reverse_lazy('horizon:admin:volumes:index')
|
||||
page_title = _("Update Volume Status")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateStatusView, self).get_context_data(**kwargs)
|
||||
context["volume_id"] = self.kwargs['volume_id']
|
||||
args = (self.kwargs['volume_id'],)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
volume_id = self.kwargs['volume_id']
|
||||
volume = cinder.volume_get(self.request, volume_id)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve volume details.'),
|
||||
redirect=self.success_url)
|
||||
return volume
|
||||
|
||||
def get_initial(self):
|
||||
volume = self.get_data()
|
||||
return {'volume_id': self.kwargs["volume_id"],
|
||||
'status': volume.status}
|
@ -3,7 +3,7 @@ PANEL = 'volumes'
|
||||
# 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 = 'admin'
|
||||
PANEL_GROUP = 'volumes'
|
||||
|
||||
# Python panel class of the PANEL to be added.
|
||||
ADD_PANEL = 'openstack_dashboard.dashboards.admin.volumes.panel.Volumes'
|
Loading…
x
Reference in New Issue
Block a user