Move Consistency Groups out of Volumes panel
Notes on enabling consistency groups in devstack: http://docs.openstack.org/admin-guide/blockstorage-consistency-groups.html You'll also need to modify the local cinder policy file. Though that's not actually enough to make it work since devstack only provides the LVM volume type and CGs don't work with LVM. You can attempt to create CGs, but they will error. Change-Id: I0ab541c81570cd5f67bb7d04c01bc92bc5cc3ab5 Implements: blueprint reorganise-volumes
This commit is contained in:
parent
921f84a7ce
commit
f85e0ffa91
|
@ -95,16 +95,16 @@
|
||||||
"snapshot_extension:snapshot_manage": "rule:admin_api",
|
"snapshot_extension:snapshot_manage": "rule:admin_api",
|
||||||
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
|
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
|
||||||
|
|
||||||
"consistencygroup:create" : "group:nobody",
|
"consistencygroup:create" : "",
|
||||||
"consistencygroup:delete": "group:nobody",
|
"consistencygroup:delete": "",
|
||||||
"consistencygroup:update": "group:nobody",
|
"consistencygroup:update": "",
|
||||||
"consistencygroup:get": "group:nobody",
|
"consistencygroup:get": "",
|
||||||
"consistencygroup:get_all": "group:nobody",
|
"consistencygroup:get_all": "",
|
||||||
|
|
||||||
"consistencygroup:create_cgsnapshot" : "group:nobody",
|
"consistencygroup:create_cgsnapshot" : "",
|
||||||
"consistencygroup:delete_cgsnapshot": "group:nobody",
|
"consistencygroup:delete_cgsnapshot": "",
|
||||||
"consistencygroup:get_cgsnapshot": "group:nobody",
|
"consistencygroup:get_cgsnapshot": "",
|
||||||
"consistencygroup:get_all_cgsnapshots": "group:nobody",
|
"consistencygroup:get_all_cgsnapshots": "",
|
||||||
|
|
||||||
"scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api",
|
"scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api",
|
||||||
"message:delete": "rule:admin_or_owner",
|
"message:delete": "rule:admin_or_owner",
|
||||||
|
|
|
@ -54,7 +54,7 @@ class UpdateForm(forms.SelfHandlingForm):
|
||||||
messages.info(request, message)
|
messages.info(request, message)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:project:volumes:index")
|
redirect = reverse("horizon:project:cgroups:index")
|
||||||
exceptions.handle(request,
|
exceptions.handle(request,
|
||||||
_('Unable to update volume consistency group.'),
|
_('Unable to update volume consistency group.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
@ -85,7 +85,7 @@ class RemoveVolsForm(forms.SelfHandlingForm):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:project:volumes:index")
|
redirect = reverse("horizon:project:groups:index")
|
||||||
exceptions.handle(request, _('Errors occurred in removing volumes '
|
exceptions.handle(request, _('Errors occurred in removing volumes '
|
||||||
'from consistency group.'),
|
'from consistency group.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
@ -110,7 +110,7 @@ class DeleteForm(forms.SelfHandlingForm):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:project:volumes:index")
|
redirect = reverse("horizon:project:cgroups:index")
|
||||||
exceptions.handle(request, _('Errors occurred in deleting '
|
exceptions.handle(request, _('Errors occurred in deleting '
|
||||||
'consistency group.'),
|
'consistency group.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
@ -143,7 +143,7 @@ class CreateSnapshotForm(forms.SelfHandlingForm):
|
||||||
messages.info(request, message)
|
messages.info(request, message)
|
||||||
return snapshot
|
return snapshot
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
redirect = reverse("horizon:project:volumes:index")
|
redirect = reverse("horizon:project:cgroups:index")
|
||||||
msg = _('Unable to create consistency group snapshot.')
|
msg = _('Unable to create consistency group snapshot.')
|
||||||
if e.code == 413:
|
if e.code == 413:
|
||||||
msg = _('Requested snapshot would exceed the allowed quota.')
|
msg = _('Requested snapshot would exceed the allowed quota.')
|
||||||
|
@ -204,7 +204,7 @@ class CloneCGroupForm(forms.SelfHandlingForm):
|
||||||
messages.info(request, message)
|
messages.info(request, message)
|
||||||
return cgroup
|
return cgroup
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:project:volumes:index")
|
redirect = reverse("horizon:project:cgroups:index")
|
||||||
msg = _('Unable to clone consistency group.')
|
msg = _('Unable to clone consistency group.')
|
||||||
|
|
||||||
search_opts = {'consistentcygroup_id': data['cgroup_id']}
|
search_opts = {'consistentcygroup_id': data['cgroup_id']}
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Copyright 2017 Rackspace, Inc.
|
||||||
|
#
|
||||||
|
# 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 CGroups(horizon.Panel):
|
||||||
|
name = _("Consistency Groups")
|
||||||
|
slug = 'cgroups'
|
||||||
|
permissions = (
|
||||||
|
('openstack.services.volume', 'openstack.services.volumev2'),
|
||||||
|
)
|
||||||
|
policy_rules = (("volume", "consistencygroup:get_all"),)
|
|
@ -23,7 +23,7 @@ from openstack_dashboard import policy
|
||||||
class CreateVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
class CreateVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "create"
|
name = "create"
|
||||||
verbose_name = _("Create Consistency Group")
|
verbose_name = _("Create Consistency Group")
|
||||||
url = "horizon:project:volumes:cgroups:create"
|
url = "horizon:project:cgroups:create"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
icon = "plus"
|
icon = "plus"
|
||||||
policy_rules = (("volume", "consistencygroup:create"),)
|
policy_rules = (("volume", "consistencygroup:create"),)
|
||||||
|
@ -32,7 +32,7 @@ class CreateVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class DeleteVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
class DeleteVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "deletecg"
|
name = "deletecg"
|
||||||
verbose_name = _("Delete Consistency Group")
|
verbose_name = _("Delete Consistency Group")
|
||||||
url = "horizon:project:volumes:cgroups:delete"
|
url = "horizon:project:cgroups:delete"
|
||||||
classes = ("ajax-modal", "btn-danger")
|
classes = ("ajax-modal", "btn-danger")
|
||||||
policy_rules = (("volume", "consistencygroup:delete"), )
|
policy_rules = (("volume", "consistencygroup:delete"), )
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class DeleteVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class RemoveAllVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
class RemoveAllVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "remove_vols"
|
name = "remove_vols"
|
||||||
verbose_name = _("Remove Volumes from Consistency Group")
|
verbose_name = _("Remove Volumes from Consistency Group")
|
||||||
url = "horizon:project:volumes:cgroups:remove_volumes"
|
url = "horizon:project:cgroups:remove_volumes"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
policy_rules = (("volume", "consistencygroup:update"), )
|
policy_rules = (("volume", "consistencygroup:update"), )
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class RemoveAllVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class EditVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
class EditVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "edit"
|
name = "edit"
|
||||||
verbose_name = _("Edit Consistency Group")
|
verbose_name = _("Edit Consistency Group")
|
||||||
url = "horizon:project:volumes:cgroups:update"
|
url = "horizon:project:cgroups:update"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
policy_rules = (("volume", "consistencygroup:update"),)
|
policy_rules = (("volume", "consistencygroup:update"),)
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class EditVolumeCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class ManageVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
class ManageVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "manage"
|
name = "manage"
|
||||||
verbose_name = _("Manage Volumes")
|
verbose_name = _("Manage Volumes")
|
||||||
url = "horizon:project:volumes:cgroups:manage"
|
url = "horizon:project:cgroups:manage"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
policy_rules = (("volume", "consistencygroup:update"),)
|
policy_rules = (("volume", "consistencygroup:update"),)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class ManageVolumes(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class CreateSnapshot(policy.PolicyTargetMixin, tables.LinkAction):
|
class CreateSnapshot(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "create_snapshot"
|
name = "create_snapshot"
|
||||||
verbose_name = _("Create Snapshot")
|
verbose_name = _("Create Snapshot")
|
||||||
url = "horizon:project:volumes:cgroups:create_snapshot"
|
url = "horizon:project:cgroups:create_snapshot"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
policy_rules = (("volume", "consistencygroup:create_cgsnapshot"),)
|
policy_rules = (("volume", "consistencygroup:create_cgsnapshot"),)
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ class CreateSnapshot(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
class CloneCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
class CloneCGroup(policy.PolicyTargetMixin, tables.LinkAction):
|
||||||
name = "clone_cgroup"
|
name = "clone_cgroup"
|
||||||
verbose_name = _("Clone Consistency Group")
|
verbose_name = _("Clone Consistency Group")
|
||||||
url = "horizon:project:volumes:cgroups:clone_cgroup"
|
url = "horizon:project:cgroups:clone_cgroup"
|
||||||
classes = ("ajax-modal",)
|
classes = ("ajax-modal",)
|
||||||
policy_rules = (("volume", "consistencygroup:create"),)
|
policy_rules = (("volume", "consistencygroup:create"),)
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ class VolumeCGroupsTable(tables.DataTable):
|
||||||
|
|
||||||
name = tables.WrappingColumn("name",
|
name = tables.WrappingColumn("name",
|
||||||
verbose_name=_("Name"),
|
verbose_name=_("Name"),
|
||||||
link="horizon:project:volumes:cgroups:detail")
|
link="horizon:project:cgroups:detail")
|
||||||
description = tables.Column("description",
|
description = tables.Column("description",
|
||||||
verbose_name=_("Description"),
|
verbose_name=_("Description"),
|
||||||
truncate=40)
|
truncate=40)
|
|
@ -19,14 +19,14 @@ from horizon import tabs
|
||||||
class OverviewTab(tabs.Tab):
|
class OverviewTab(tabs.Tab):
|
||||||
name = _("Overview")
|
name = _("Overview")
|
||||||
slug = "overview"
|
slug = "overview"
|
||||||
template_name = ("project/volumes/cgroups/_detail_overview.html")
|
template_name = ("project/cgroups/_detail_overview.html")
|
||||||
|
|
||||||
def get_context_data(self, request):
|
def get_context_data(self, request):
|
||||||
cgroup = self.tab_group.kwargs['cgroup']
|
cgroup = self.tab_group.kwargs['cgroup']
|
||||||
return {"cgroup": cgroup}
|
return {"cgroup": cgroup}
|
||||||
|
|
||||||
def get_redirect_url(self):
|
def get_redirect_url(self):
|
||||||
return reverse('horizon:project:volumes:index')
|
return reverse('horizon:project:cgroups:index')
|
||||||
|
|
||||||
|
|
||||||
class CGroupsDetailTabs(tabs.TabGroup):
|
class CGroupsDetailTabs(tabs.TabGroup):
|
|
@ -19,9 +19,7 @@ from openstack_dashboard.api import cinder
|
||||||
from openstack_dashboard.test import helpers as test
|
from openstack_dashboard.test import helpers as test
|
||||||
|
|
||||||
|
|
||||||
VOLUME_INDEX_URL = reverse('horizon:project:volumes:index')
|
INDEX_URL = reverse('horizon:project:cgroups:index')
|
||||||
VOLUME_CGROUPS_TAB_URL = urlunquote(reverse(
|
|
||||||
'horizon:project:volumes:cgroups_tab'))
|
|
||||||
VOLUME_CGROUPS_SNAP_TAB_URL = urlunquote(reverse(
|
VOLUME_CGROUPS_SNAP_TAB_URL = urlunquote(reverse(
|
||||||
'horizon:project:volumes:cg_snapshots_tab'))
|
'horizon:project:volumes:cg_snapshots_tab'))
|
||||||
|
|
||||||
|
@ -62,10 +60,10 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cgroup)
|
.AndReturn(cgroup)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:create')
|
url = reverse('horizon:project:cgroups:create')
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('extension_supported',
|
@test.create_stubs({cinder: ('extension_supported',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
@ -101,10 +99,10 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndRaise(self.exceptions.cinder)
|
.AndRaise(self.exceptions.cinder)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:create')
|
url = reverse('horizon:project:cgroups:create')
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
self.assertIn("Unable to create consistency group.",
|
self.assertIn("Unable to create consistency group.",
|
||||||
res.cookies.output())
|
res.cookies.output())
|
||||||
|
|
||||||
|
@ -119,11 +117,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
force=False)
|
force=False)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:delete',
|
url = reverse('horizon:project:cgroups:delete',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url)
|
res = self.client.post(url)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_get',
|
@test.create_stubs({cinder: ('volume_cgroup_get',
|
||||||
'volume_cgroup_delete')})
|
'volume_cgroup_delete')})
|
||||||
|
@ -137,11 +135,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
force=True)
|
force=True)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:delete',
|
url = reverse('horizon:project:cgroups:delete',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_get',
|
@test.create_stubs({cinder: ('volume_cgroup_get',
|
||||||
'volume_cgroup_delete')})
|
'volume_cgroup_delete')})
|
||||||
|
@ -157,11 +155,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
AndRaise(self.exceptions.cinder)
|
AndRaise(self.exceptions.cinder)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:delete',
|
url = reverse('horizon:project:cgroups:delete',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_update',
|
@test.create_stubs({cinder: ('volume_cgroup_update',
|
||||||
'volume_cgroup_get')})
|
'volume_cgroup_get')})
|
||||||
|
@ -183,11 +181,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cgroup)
|
.AndReturn(cgroup)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:update',
|
url = reverse('horizon:project:cgroups:update',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_update',
|
@test.create_stubs({cinder: ('volume_cgroup_update',
|
||||||
'volume_cgroup_get')})
|
'volume_cgroup_get')})
|
||||||
|
@ -209,11 +207,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cgroup)
|
.AndReturn(cgroup)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:update',
|
url = reverse('horizon:project:cgroups:update',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_update',
|
@test.create_stubs({cinder: ('volume_cgroup_update',
|
||||||
'volume_cgroup_get')})
|
'volume_cgroup_get')})
|
||||||
|
@ -233,11 +231,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cgroup)
|
.AndReturn(cgroup)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:update',
|
url = reverse('horizon:project:cgroups:update',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_update',
|
@test.create_stubs({cinder: ('volume_cgroup_update',
|
||||||
'volume_cgroup_get')})
|
'volume_cgroup_get')})
|
||||||
|
@ -257,11 +255,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndRaise(self.exceptions.cinder)
|
.AndRaise(self.exceptions.cinder)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:update',
|
url = reverse('horizon:project:cgroups:update',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cgroup_get',)})
|
@test.create_stubs({cinder: ('volume_cgroup_get',)})
|
||||||
def test_detail_view_with_exception(self):
|
def test_detail_view_with_exception(self):
|
||||||
|
@ -272,11 +270,11 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:detail',
|
url = reverse('horizon:project:cgroups:detail',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.get(url)
|
res = self.client.get(url)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_cg_snapshot_create',)})
|
@test.create_stubs({cinder: ('volume_cg_snapshot_create',)})
|
||||||
def test_create_snapshot(self):
|
def test_create_snapshot(self):
|
||||||
|
@ -294,7 +292,7 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cg_snapshot)
|
.AndReturn(cg_snapshot)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:create_snapshot',
|
url = reverse('horizon:project:cgroups:create_snapshot',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
|
@ -315,8 +313,8 @@ class ConsistencyGroupTests(test.TestCase):
|
||||||
.AndReturn(cgroup)
|
.AndReturn(cgroup)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:project:volumes:cgroups:clone_cgroup',
|
url = reverse('horizon:project:cgroups:clone_cgroup',
|
||||||
args=[cgroup.id])
|
args=[cgroup.id])
|
||||||
res = self.client.post(url, formData)
|
res = self.client.post(url, formData)
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, VOLUME_CGROUPS_TAB_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
|
@ -12,10 +12,11 @@
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project.volumes.cgroups import views
|
from openstack_dashboard.dashboards.project.cgroups import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
url(r'^$', views.CGroupsView.as_view(), name='index'),
|
||||||
url(r'^create/$',
|
url(r'^create/$',
|
||||||
views.CreateView.as_view(),
|
views.CreateView.as_view(),
|
||||||
name='create'),
|
name='create'),
|
|
@ -16,6 +16,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
from horizon import tabs
|
from horizon import tabs
|
||||||
from horizon.utils import memoized
|
from horizon.utils import memoized
|
||||||
from horizon import workflows
|
from horizon import workflows
|
||||||
|
@ -24,33 +25,49 @@ from openstack_dashboard import api
|
||||||
from openstack_dashboard.api import cinder
|
from openstack_dashboard.api import cinder
|
||||||
from openstack_dashboard.usage import quotas
|
from openstack_dashboard.usage import quotas
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project.volumes \
|
from openstack_dashboard.dashboards.project.cgroups \
|
||||||
.cgroups import workflows as vol_cgroup_workflows
|
import forms as vol_cgroup_forms
|
||||||
from openstack_dashboard.dashboards.project.volumes \
|
from openstack_dashboard.dashboards.project.cgroups \
|
||||||
.cgroups import forms as vol_cgroup_forms
|
import tables as vol_cgroup_tables
|
||||||
from openstack_dashboard.dashboards.project.volumes \
|
from openstack_dashboard.dashboards.project.cgroups \
|
||||||
.cgroups import tables as vol_cgroup_tables
|
import tabs as vol_cgroup_tabs
|
||||||
from openstack_dashboard.dashboards.project.volumes \
|
from openstack_dashboard.dashboards.project.cgroups \
|
||||||
.cgroups import tabs as vol_cgroup_tabs
|
import workflows as vol_cgroup_workflows
|
||||||
|
|
||||||
CGROUP_INFO_FIELDS = ("name",
|
CGROUP_INFO_FIELDS = ("name",
|
||||||
"description")
|
"description")
|
||||||
|
|
||||||
INDEX_URL = "horizon:project:volumes:index"
|
INDEX_URL = "horizon:project:cgroups:index"
|
||||||
|
|
||||||
|
|
||||||
|
class CGroupsView(tables.DataTableView):
|
||||||
|
table_class = vol_cgroup_tables.VolumeCGroupsTable
|
||||||
|
page_title = _("Consistency Groups")
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
cgroups = api.cinder.volume_cgroup_list_with_vol_type_names(
|
||||||
|
self.request)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
cgroups = []
|
||||||
|
exceptions.handle(self.request, _("Unable to retrieve "
|
||||||
|
"volume consistency groups."))
|
||||||
|
return cgroups
|
||||||
|
|
||||||
|
|
||||||
class CreateView(workflows.WorkflowView):
|
class CreateView(workflows.WorkflowView):
|
||||||
workflow_class = vol_cgroup_workflows.CreateCGroupWorkflow
|
workflow_class = vol_cgroup_workflows.CreateCGroupWorkflow
|
||||||
template_name = 'project/volumes/cgroups/create.html'
|
template_name = 'project/cgroups/create.html'
|
||||||
page_title = _("Create Volume Consistency Group")
|
page_title = _("Create Volume Consistency Group")
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(forms.ModalFormView):
|
class UpdateView(forms.ModalFormView):
|
||||||
template_name = 'project/volumes/cgroups/update.html'
|
template_name = 'project/cgroups/update.html'
|
||||||
page_title = _("Edit Consistency Group")
|
page_title = _("Edit Consistency Group")
|
||||||
form_class = vol_cgroup_forms.UpdateForm
|
form_class = vol_cgroup_forms.UpdateForm
|
||||||
success_url = reverse_lazy('horizon:project:volumes:index')
|
success_url = reverse_lazy('horizon:project:cgroups:index')
|
||||||
submit_url = "horizon:project:volumes:cgroups:update"
|
submit_url = "horizon:project:cgroups:update"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
cgroup = self.get_object()
|
cgroup = self.get_object()
|
||||||
|
@ -78,11 +95,11 @@ class UpdateView(forms.ModalFormView):
|
||||||
|
|
||||||
|
|
||||||
class RemoveVolumesView(forms.ModalFormView):
|
class RemoveVolumesView(forms.ModalFormView):
|
||||||
template_name = 'project/volumes/cgroups/remove_vols.html'
|
template_name = 'project/cgroups/remove_vols.html'
|
||||||
page_title = _("Remove Volumes from Consistency Group")
|
page_title = _("Remove Volumes from Consistency Group")
|
||||||
form_class = vol_cgroup_forms.RemoveVolsForm
|
form_class = vol_cgroup_forms.RemoveVolsForm
|
||||||
success_url = reverse_lazy('horizon:project:volumes:index')
|
success_url = reverse_lazy('horizon:project:cgroups:index')
|
||||||
submit_url = "horizon:project:volumes:cgroups:remove_volumes"
|
submit_url = "horizon:project:cgroups:remove_volumes"
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
cgroup = self.get_object()
|
cgroup = self.get_object()
|
||||||
|
@ -109,11 +126,11 @@ class RemoveVolumesView(forms.ModalFormView):
|
||||||
|
|
||||||
|
|
||||||
class DeleteView(forms.ModalFormView):
|
class DeleteView(forms.ModalFormView):
|
||||||
template_name = 'project/volumes/cgroups/delete.html'
|
template_name = 'project/cgroups/delete.html'
|
||||||
page_title = _("Delete Consistency Group")
|
page_title = _("Delete Consistency Group")
|
||||||
form_class = vol_cgroup_forms.DeleteForm
|
form_class = vol_cgroup_forms.DeleteForm
|
||||||
success_url = reverse_lazy('horizon:project:volumes:index')
|
success_url = reverse_lazy('horizon:project:cgroups:index')
|
||||||
submit_url = "horizon:project:volumes:cgroups:delete"
|
submit_url = "horizon:project:cgroups:delete"
|
||||||
submit_label = page_title
|
submit_label = page_title
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
|
@ -170,9 +187,9 @@ class ManageView(workflows.WorkflowView):
|
||||||
class CreateSnapshotView(forms.ModalFormView):
|
class CreateSnapshotView(forms.ModalFormView):
|
||||||
form_class = vol_cgroup_forms.CreateSnapshotForm
|
form_class = vol_cgroup_forms.CreateSnapshotForm
|
||||||
page_title = _("Create Consistency Group Snapshot")
|
page_title = _("Create Consistency Group Snapshot")
|
||||||
template_name = 'project/volumes/cgroups/create_snapshot.html'
|
template_name = 'project/cgroups/create_snapshot.html'
|
||||||
submit_label = _("Create Snapshot")
|
submit_label = _("Create Snapshot")
|
||||||
submit_url = "horizon:project:volumes:cgroups:create_snapshot"
|
submit_url = "horizon:project:cgroups:create_snapshot"
|
||||||
success_url = reverse_lazy('horizon:project:volumes:cg_snapshots_tab')
|
success_url = reverse_lazy('horizon:project:volumes:cg_snapshots_tab')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -212,10 +229,10 @@ class CreateSnapshotView(forms.ModalFormView):
|
||||||
class CloneCGroupView(forms.ModalFormView):
|
class CloneCGroupView(forms.ModalFormView):
|
||||||
form_class = vol_cgroup_forms.CloneCGroupForm
|
form_class = vol_cgroup_forms.CloneCGroupForm
|
||||||
page_title = _("Clone Consistency Group")
|
page_title = _("Clone Consistency Group")
|
||||||
template_name = 'project/volumes/cgroups/clone_cgroup.html'
|
template_name = 'project/cgroups/clone_cgroup.html'
|
||||||
submit_label = _("Clone Consistency Group")
|
submit_label = _("Clone Consistency Group")
|
||||||
submit_url = "horizon:project:volumes:cgroups:clone_cgroup"
|
submit_url = "horizon:project:cgroups:clone_cgroup"
|
||||||
success_url = reverse_lazy('horizon:project:volumes:cgroups_tab')
|
success_url = reverse_lazy('horizon:project:cgroups:index')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(CloneCGroupView, self).get_context_data(**kwargs)
|
context = super(CloneCGroupView, self).get_context_data(**kwargs)
|
||||||
|
@ -296,7 +313,7 @@ class DetailView(tabs.TabView):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_redirect_url():
|
def get_redirect_url():
|
||||||
return reverse('horizon:project:volumes:index')
|
return reverse('horizon:project:cgroups:index')
|
||||||
|
|
||||||
def get_tabs(self, request, *args, **kwargs):
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
cgroup = self.get_data()
|
cgroup = self.get_data()
|
|
@ -20,7 +20,7 @@ from horizon import workflows
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
from openstack_dashboard.api import cinder
|
from openstack_dashboard.api import cinder
|
||||||
|
|
||||||
INDEX_URL = "horizon:project:volumes:index"
|
INDEX_URL = "horizon:project:cgroups:index"
|
||||||
CGROUP_VOLUME_MEMBER_SLUG = "update_members"
|
CGROUP_VOLUME_MEMBER_SLUG = "update_members"
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class CreateCGroupView(forms.ModalFormView):
|
||||||
form_class = cg_snapshot_forms.CreateCGroupForm
|
form_class = cg_snapshot_forms.CreateCGroupForm
|
||||||
template_name = 'project/volumes/cg_snapshots/create.html'
|
template_name = 'project/volumes/cg_snapshots/create.html'
|
||||||
submit_url = "horizon:project:volumes:cg_snapshots:create_cgroup"
|
submit_url = "horizon:project:volumes:cg_snapshots:create_cgroup"
|
||||||
success_url = reverse_lazy('horizon:project:volumes:cgroups_tab')
|
success_url = reverse_lazy('horizon:project:cgroups:index')
|
||||||
page_title = _("Create Volume Consistency Group")
|
page_title = _("Create Volume Consistency Group")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -25,8 +25,6 @@ from openstack_dashboard import policy
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project.volumes.cg_snapshots \
|
from openstack_dashboard.dashboards.project.volumes.cg_snapshots \
|
||||||
import tables as cg_snapshots_tables
|
import tables as cg_snapshots_tables
|
||||||
from openstack_dashboard.dashboards.project.volumes.cgroups \
|
|
||||||
import tables as cgroup_tables
|
|
||||||
from openstack_dashboard.dashboards.project.volumes.volumes \
|
from openstack_dashboard.dashboards.project.volumes.volumes \
|
||||||
import tables as volume_tables
|
import tables as volume_tables
|
||||||
|
|
||||||
|
@ -124,31 +122,6 @@ class VolumeTab(PagedTableMixin, tabs.TableTab, VolumeTableMixIn):
|
||||||
return volumes
|
return volumes
|
||||||
|
|
||||||
|
|
||||||
class CGroupsTab(tabs.TableTab):
|
|
||||||
table_classes = (cgroup_tables.VolumeCGroupsTable,)
|
|
||||||
name = _("Consistency Groups")
|
|
||||||
slug = "cgroups_tab"
|
|
||||||
template_name = ("horizon/common/_detail_table.html")
|
|
||||||
preload = False
|
|
||||||
|
|
||||||
def allowed(self, request):
|
|
||||||
return policy.check(
|
|
||||||
(("volume", "consistencygroup:get_all"),),
|
|
||||||
request
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_volume_cgroups_data(self):
|
|
||||||
try:
|
|
||||||
cgroups = api.cinder.volume_cgroup_list_with_vol_type_names(
|
|
||||||
self.request)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
cgroups = []
|
|
||||||
exceptions.handle(self.request, _("Unable to retrieve "
|
|
||||||
"volume consistency groups."))
|
|
||||||
return cgroups
|
|
||||||
|
|
||||||
|
|
||||||
class CGSnapshotsTab(tabs.TableTab):
|
class CGSnapshotsTab(tabs.TableTab):
|
||||||
table_classes = (cg_snapshots_tables.CGSnapshotsTable,)
|
table_classes = (cg_snapshots_tables.CGSnapshotsTable,)
|
||||||
name = _("Consistency Group Snapshots")
|
name = _("Consistency Group Snapshots")
|
||||||
|
@ -176,5 +149,5 @@ class CGSnapshotsTab(tabs.TableTab):
|
||||||
|
|
||||||
class VolumeAndSnapshotTabs(tabs.TabGroup):
|
class VolumeAndSnapshotTabs(tabs.TabGroup):
|
||||||
slug = "volumes_and_snapshots"
|
slug = "volumes_and_snapshots"
|
||||||
tabs = (VolumeTab, CGroupsTab, CGSnapshotsTab)
|
tabs = (VolumeTab, CGSnapshotsTab)
|
||||||
sticky = True
|
sticky = True
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<dd>{{ cg_snapshot.status|capfirst }}</dd>
|
<dd>{{ cg_snapshot.status|capfirst }}</dd>
|
||||||
<dt>{% trans "Consistency Group" %}</dt>
|
<dt>{% trans "Consistency Group" %}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<a href="{% url 'horizon:project:volumes:cgroups:detail' cg_snapshot.consistencygroup_id %}">
|
<a href="{% url 'horizon:project:cgroups:detail' cg_snapshot.consistencygroup_id %}">
|
||||||
{% if cg_snapshot.cg_name %}
|
{% if cg_snapshot.cg_name %}
|
||||||
{{ cg_snapshot.cg_name }}
|
{{ cg_snapshot.cg_name }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -17,8 +17,6 @@ from django.conf.urls import url
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project.volumes.cg_snapshots \
|
from openstack_dashboard.dashboards.project.volumes.cg_snapshots \
|
||||||
import urls as cg_snapshots_urls
|
import urls as cg_snapshots_urls
|
||||||
from openstack_dashboard.dashboards.project.volumes.cgroups \
|
|
||||||
import urls as cgroup_urls
|
|
||||||
from openstack_dashboard.dashboards.project.volumes import views
|
from openstack_dashboard.dashboards.project.volumes import views
|
||||||
from openstack_dashboard.dashboards.project.volumes.volumes \
|
from openstack_dashboard.dashboards.project.volumes.volumes \
|
||||||
import urls as volume_urls
|
import urls as volume_urls
|
||||||
|
@ -27,16 +25,11 @@ urlpatterns = [
|
||||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
url(r'^\?tab=volumes_and_snapshots__volumes_tab$',
|
url(r'^\?tab=volumes_and_snapshots__volumes_tab$',
|
||||||
views.IndexView.as_view(), name='volumes_tab'),
|
views.IndexView.as_view(), name='volumes_tab'),
|
||||||
url(r'^\?tab=volumes_and_snapshots__cgroups_tab$',
|
|
||||||
views.IndexView.as_view(), name='cgroups_tab'),
|
|
||||||
url(r'^\?tab=volumes_and_snapshots__cg_snapshots_tab$',
|
url(r'^\?tab=volumes_and_snapshots__cg_snapshots_tab$',
|
||||||
views.IndexView.as_view(), name='cg_snapshots_tab'),
|
views.IndexView.as_view(), name='cg_snapshots_tab'),
|
||||||
url(r'', include(
|
url(r'', include(
|
||||||
volume_urls,
|
volume_urls,
|
||||||
namespace='volumes')),
|
namespace='volumes')),
|
||||||
url(r'cgroups/', include(
|
|
||||||
cgroup_urls,
|
|
||||||
namespace='cgroups')),
|
|
||||||
url(r'cg_snapshots/', include(
|
url(r'cg_snapshots/', include(
|
||||||
cg_snapshots_urls,
|
cg_snapshots_urls,
|
||||||
namespace='cg_snapshots')),
|
namespace='cg_snapshots')),
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL = 'cgroups'
|
||||||
|
# The slug of the dashboard the PANEL associated with. Required.
|
||||||
|
PANEL_DASHBOARD = 'project'
|
||||||
|
# The slug of the panel group the PANEL is associated with.
|
||||||
|
PANEL_GROUP = 'volumes'
|
||||||
|
|
||||||
|
# Python panel class of the PANEL to be added.
|
||||||
|
ADD_PANEL = 'openstack_dashboard.dashboards.project.cgroups.panel.CGroups'
|
Loading…
Reference in New Issue