Look for volumev2 endpoints instead of volume

Volumes tabs should be enabled when volumev2 endpoint is registered.
Currently, Horizon considers no volume service is running if there
is no V1 endpoint, which doesn't make sense as Horizon no longer
supports the cinder V1 protocol.

Co-Authored-By: itxaka <itxaka@redhat.com>
Change-Id: I35d821eedb75f73f9330ed11f921694104eed0c6
Closes-Bug: 1415712
This commit is contained in:
IWAMOTO Toshihiro
2015-01-29 12:05:04 +09:00
committed by Itxaka
parent e21885d11f
commit 2e59431227
21 changed files with 103 additions and 86 deletions

View File

@@ -785,3 +785,10 @@ def pool_list(request, detailed=False):
return [VolumePool(v) for v in c_client.pools.list(
detailed=detailed)]
def is_volume_service_enabled(request):
return bool(
base.is_service_enabled(request, 'volume') or
base.is_service_enabled(request, 'volumev2')
)

View File

@@ -40,11 +40,12 @@ class ServicesViewTests(test.BaseAdminViewTests):
# should be in the list.
self.mox.StubOutWithMock(api.nova, 'default_quota_get')
self.mox.StubOutWithMock(api.cinder, 'default_quota_get')
self.mox.StubOutWithMock(api.cinder, 'is_volume_service_enabled')
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
if neutron_enabled:
self.mox.StubOutWithMock(api.neutron, 'is_extension_supported')
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(neutron_enabled)

View File

@@ -21,7 +21,6 @@ from horizon import workflows
import logging
from openstack_dashboard.api import base
from openstack_dashboard.api import cinder
from openstack_dashboard.api import nova
from openstack_dashboard.usage import quotas
@@ -94,7 +93,7 @@ class UpdateDefaultQuotas(workflows.Workflow):
if key != 'fixed_ips'])
is_error_nova = False
is_error_cinder = False
is_volume_service_enabled = base.is_service_enabled(request, 'volume')
is_volume_service_enabled = cinder.is_volume_service_enabled(request)
# Update the default quotas for nova.
try:

View File

@@ -65,7 +65,9 @@ class CinderServicesTab(tabs.TableTab):
name = tables.CinderServicesTable.Meta.verbose_name
slug = tables.CinderServicesTable.Meta.name
template_name = constants.INFO_DETAIL_TEMPLATE_NAME
permissions = ('openstack.services.volume',)
permissions = (
('openstack.services.volume', 'openstack.services.volumev2'),
)
def get_cinder_services_data(self):
try:

View File

@@ -63,7 +63,6 @@ class SystemInfoViewTests(test.BaseAdminViewTests):
self.assertQuerysetEqual(
services_tab._tables['services'].data,
['<Service: compute>',
'<Service: volume>',
'<Service: volumev2>',
'<Service: image>',
'<Service: identity (native backend)>',

View File

@@ -18,4 +18,6 @@ import horizon
class Volumes(horizon.Panel):
name = _("Volumes")
slug = "volumes"
permissions = ('openstack.services.volume',)
permissions = (
('openstack.services.volume', 'openstack.services.volumev2'),
)

View File

@@ -16,7 +16,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tabs
from openstack_dashboard import api
from openstack_dashboard.api import cinder
from openstack_dashboard.api import keystone
@@ -119,7 +118,7 @@ class SnapshotTab(volumes_tabs.PagedTableMixin, tabs.TableTab):
preload = False
def get_volume_snapshots_data(self):
if api.base.is_service_enabled(self.request, 'volume'):
if cinder.is_volume_service_enabled(self.request):
try:
marker, sort_dir = self._get_marker()
snapshots, self._has_more_data, self._has_prev_data = \

View File

@@ -167,6 +167,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
'group_list',
'role_list'),
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',),
api.neutron: ('is_extension_supported',),
quotas: ('get_default_quota_data',)})
def test_add_project_get(self):
@@ -181,7 +182,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
# init
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
.AndReturn(default_domain)
@@ -1730,6 +1731,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
'group_list',
'role_list'),
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',),
quotas: ('get_default_quota_data',)})
def test_membership_list_loads_correctly(self):
member_css_class = ".available_members"
@@ -1737,7 +1739,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(False)
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
.AndReturn(self.domain)

View File

@@ -28,7 +28,6 @@ from horizon.utils import memoized
from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.api import base
from openstack_dashboard.api import cinder
from openstack_dashboard.api import keystone
from openstack_dashboard.api import nova
@@ -399,7 +398,7 @@ class CommonQuotaWorkflow(workflows.Workflow):
[(key, data[key]) for key in quotas.NOVA_QUOTA_FIELDS])
nova.tenant_quota_update(request, project_id, **nova_data)
if base.is_service_enabled(request, 'volume'):
if cinder.is_volume_service_enabled(request):
cinder_data = dict([(key, data[key]) for key in
quotas.CINDER_QUOTA_FIELDS])
cinder.tenant_quota_update(request,

View File

@@ -355,13 +355,14 @@ class FloatingIpNeutronViewTests(FloatingIpViewTests):
'network_list',
'router_list',
'subnet_list'),
api.base: ('is_service_enabled',)})
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
@test.update_settings(OPENSTACK_NEUTRON_NETWORK={'enable_quotas': True})
def test_correct_quotas_displayed(self):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(True)
@@ -413,13 +414,14 @@ class FloatingIpNeutronViewTests(FloatingIpViewTests):
'network_list',
'router_list',
'subnet_list'),
api.base: ('is_service_enabled',)})
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
@test.update_settings(OPENSTACK_NEUTRON_NETWORK={'enable_quotas': True})
def test_correct_quotas_displayed_shared_networks(self):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(True)

View File

@@ -26,7 +26,6 @@ from horizon import tables
from horizon.utils.memoized import memoized # noqa
from openstack_dashboard import api
from openstack_dashboard.api import base
NOT_LAUNCHABLE_FORMATS = ['aki', 'ari']
@@ -157,7 +156,7 @@ class CreateVolumeFromImage(tables.LinkAction):
def allowed(self, request, image=None):
if (image and image.container_format not in NOT_LAUNCHABLE_FORMATS
and base.is_service_enabled(request, 'volume')):
and api.cinder.is_volume_service_enabled(request)):
return image.status == "active"
return False

View File

@@ -156,7 +156,7 @@ class SetInstanceDetailsAction(workflows.Action):
("image_id", _("Boot from image")),
("instance_snapshot_id", _("Boot from snapshot")),
]
if base.is_service_enabled(request, 'volume'):
if cinder.is_volume_service_enabled(request):
source_type_choices.append(("volume_id", _("Boot from volume")))
try:
@@ -467,8 +467,7 @@ class SetInstanceDetailsAction(workflows.Action):
def populate_volume_id_choices(self, request, context):
volumes = []
try:
if (base.is_service_enabled(request, 'volume')
or base.is_service_enabled(request, 'volumev2')):
if cinder.is_volume_service_enabled(request):
available = api.cinder.VOLUME_STATE_AVAILABLE
volumes = [self._get_volume_display_name(v)
for v in cinder.volume_list(self.request,
@@ -485,8 +484,7 @@ class SetInstanceDetailsAction(workflows.Action):
def populate_volume_snapshot_id_choices(self, request, context):
snapshots = []
try:
if (base.is_service_enabled(request, 'volume')
or base.is_service_enabled(request, 'volumev2')):
if cinder.is_volume_service_enabled(request):
available = api.cinder.VOLUME_STATE_AVAILABLE
snapshots = [self._get_volume_display_name(s)
for s in cinder.volume_snapshot_list(

View File

@@ -130,13 +130,14 @@ class UsageViewTests(test.TestCase):
def test_usage_nova_network_disabled(self):
self._test_usage_nova_network(nova_stu_enabled=False)
@test.create_stubs({api.base: ('is_service_enabled',)})
@test.create_stubs({api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
def _test_usage_nova_network(self, nova_stu_enabled):
self._stub_nova_api_calls(nova_stu_enabled)
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(False)
self.mox.ReplayAll()
@@ -307,7 +308,8 @@ class UsageViewTests(test.TestCase):
def test_usage_without_cinder(self):
self._test_usage_cinder(cinder_enabled=False)
@test.create_stubs({api.base: ('is_service_enabled',)})
@test.create_stubs({api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
def _test_usage_cinder(self, cinder_enabled):
self._stub_nova_api_calls(True)
@@ -316,7 +318,7 @@ class UsageViewTests(test.TestCase):
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest), 'volume') \
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(cinder_enabled)
self.mox.ReplayAll()

View File

@@ -20,4 +20,6 @@ import horizon
class Volumes(horizon.Panel):
name = _("Volumes")
slug = 'volumes'
permissions = ('openstack.services.volume',)
permissions = (
('openstack.services.volume', 'openstack.services.volumev2'),
)

View File

@@ -22,7 +22,6 @@ from django.utils.translation import ungettext_lazy
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.api import base
from openstack_dashboard.api import cinder
from openstack_dashboard import policy
@@ -102,7 +101,7 @@ class CreateVolumeFromSnapshot(tables.LinkAction):
return "?".join([base_url, params])
def allowed(self, request, volume=None):
if volume and base.is_service_enabled(request, 'volume'):
if volume and cinder.is_volume_service_enabled(request):
return volume.status == "available"
return False
@@ -161,4 +160,6 @@ class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
EditVolumeSnapshot, DeleteVolumeSnapshot)
row_class = UpdateRow
status_columns = ("status",)
permissions = ['openstack.services.volume']
permissions = [(
('openstack.services.volume', 'openstack.services.volumev2'),
)]

View File

@@ -138,19 +138,20 @@ class SnapshotTab(PagedTableMixin, tabs.TableTab):
preload = False
def get_volume_snapshots_data(self):
try:
marker, sort_dir = self._get_marker()
snapshots, self._has_more_data, self._has_prev_data = \
api.cinder.volume_snapshot_list_paged(
self.request, paginate=True, marker=marker,
sort_dir=sort_dir)
volumes = api.cinder.volume_list(self.request)
volumes = dict((v.id, v) for v in volumes)
except Exception:
snapshots = []
volumes = {}
exceptions.handle(self.request, _("Unable to retrieve "
"volume snapshots."))
snapshots = []
volumes = {}
if api.base.is_service_enabled(self.request, 'volumev2'):
try:
marker, sort_dir = self._get_marker()
snapshots, self._has_more_data, self._has_prev_data = \
api.cinder.volume_snapshot_list_paged(
self.request, paginate=True, marker=marker,
sort_dir=sort_dir)
volumes = api.cinder.volume_list(self.request)
volumes = dict((v.id, v) for v in volumes)
except Exception:
exceptions.handle(self.request, _("Unable to retrieve "
"volume snapshots."))
for snapshot in snapshots:
volume = volumes.get(snapshot.volume_id)

View File

@@ -202,16 +202,16 @@ class ApiHelperTests(test.TestCase):
endpoint_type='adminURL')
self.assertEqual('http://admin.nova.example.com:8774/v2', url)
url = api_base.url_for(self.request, 'volume')
self.assertEqual('http://public.nova.example.com:8776/v1', url)
url = api_base.url_for(self.request, 'volumev2')
self.assertEqual('http://public.nova.example.com:8776/v2', url)
url = api_base.url_for(self.request, 'volume',
url = api_base.url_for(self.request, 'volumev2',
endpoint_type="internalURL")
self.assertEqual('http://int.nova.example.com:8776/v1', url)
self.assertEqual('http://int.nova.example.com:8776/v2', url)
url = api_base.url_for(self.request, 'volume',
url = api_base.url_for(self.request, 'volumev2',
endpoint_type='adminURL')
self.assertEqual('http://admin.nova.example.com:8776/v1', url)
self.assertEqual('http://admin.nova.example.com:8776/v2', url)
self.assertNotIn('notAnApi', self.request.user.service_catalog,
'Select a new nonexistent service catalog key')

View File

@@ -51,18 +51,6 @@ SERVICE_CATALOG = [
"adminURL": "http://admin.nova2.example.com:8774/v2",
"internalURL": "http://int.nova2.example.com:8774/v2",
"publicURL": "http://public.nova2.example.com:8774/v2"}]},
{"type": "volume",
"name": "cinder",
"endpoints_links": [],
"endpoints": [
{"region": "RegionOne",
"adminURL": "http://admin.nova.example.com:8776/v1",
"internalURL": "http://int.nova.example.com:8776/v1",
"publicURL": "http://public.nova.example.com:8776/v1"},
{"region": "RegionTwo",
"adminURL": "http://admin.nova.example.com:8776/v1",
"internalURL": "http://int.nova.example.com:8776/v1",
"publicURL": "http://public.nova.example.com:8776/v1"}]},
{"type": "volumev2",
"name": "cinderv2",
"endpoints_links": [],

View File

@@ -58,13 +58,15 @@ class QuotaTests(test.APITestCase):
'floating_ip_supported'),
api.base: ('is_service_enabled',),
cinder: ('volume_list', 'volume_snapshot_list',
'tenant_quota_get',)})
'tenant_quota_get',
'is_volume_service_enabled')})
def test_tenant_quota_usages(self):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.flavor_list(IsA(http.HttpRequest)) \
@@ -100,13 +102,15 @@ class QuotaTests(test.APITestCase):
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',
'floating_ip_supported'),
api.base: ('is_service_enabled',)})
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
def test_tenant_quota_usages_without_volume(self):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(False)
api.cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.flavor_list(IsA(http.HttpRequest)) \
@@ -140,10 +144,12 @@ class QuotaTests(test.APITestCase):
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',
'floating_ip_supported'),
api.base: ('is_service_enabled',)})
api.base: ('is_service_enabled',),
api.cinder: ('is_volume_service_enabled',)})
def test_tenant_quota_usages_no_instances_running(self):
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(False)
api.cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(False)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.flavor_list(IsA(http.HttpRequest)) \
@@ -180,15 +186,17 @@ class QuotaTests(test.APITestCase):
'floating_ip_supported'),
api.base: ('is_service_enabled',),
cinder: ('volume_list', 'volume_snapshot_list',
'tenant_quota_get',)})
'tenant_quota_get',
'is_volume_service_enabled')})
def test_tenant_quota_usages_unlimited_quota(self):
inf_quota = self.quotas.first()
inf_quota['ram'] = -1
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.flavor_list(IsA(http.HttpRequest)) \
@@ -229,13 +237,15 @@ class QuotaTests(test.APITestCase):
'floating_ip_supported'),
api.base: ('is_service_enabled',),
cinder: ('volume_list', 'volume_snapshot_list',
'tenant_quota_get',)})
'tenant_quota_get',
'is_volume_service_enabled')})
def test_tenant_quota_usages_neutron_fip_disabled(self):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.flavor_list(IsA(http.HttpRequest)) \
@@ -279,11 +289,13 @@ class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('tenant_quota_get',),
api.base: ('is_service_enabled',),
api.cinder: ('tenant_quota_get',),
api.cinder: ('tenant_quota_get',
'is_volume_service_enabled'),
exceptions: ('handle',)})
def test_get_quota_data_cinder_exception(self):
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
api.cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest),
'network').AndReturn(False)
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
@@ -298,11 +310,13 @@ class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('tenant_absolute_limits',),
api.base: ('is_service_enabled',),
api.cinder: ('tenant_absolute_limits',),
api.cinder: ('tenant_absolute_limits',
'is_volume_service_enabled'),
exceptions: ('handle',)})
def test_tenant_limit_usages_cinder_exception(self):
api.base.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
api.cinder.is_volume_service_enabled(
IsA(http.HttpRequest)
).AndReturn(True)
api.nova.tenant_absolute_limits(IsA(http.HttpRequest)).AndReturn({})
api.cinder.tenant_absolute_limits(IsA(http.HttpRequest)) \
.AndRaise(cinder.cinder_exception.ClientException('test'))

View File

@@ -178,7 +178,7 @@ class BaseUsage(object):
def get_cinder_limits(self):
"""Get volume limits if cinder is enabled."""
if not api.base.is_service_enabled(self.request, 'volume'):
if not api.cinder.is_volume_service_enabled(self.request):
return
try:
self.limits.update(api.cinder.tenant_absolute_limits(self.request))

View File

@@ -231,7 +231,7 @@ def get_disabled_quotas(request):
disabled_quotas = []
# Cinder
if not base.is_service_enabled(request, 'volume'):
if not cinder.is_volume_service_enabled(request):
disabled_quotas.extend(CINDER_QUOTA_FIELDS)
# Neutron
@@ -390,7 +390,7 @@ def tenant_limit_usages(request):
msg = _("Unable to retrieve compute limit information.")
exceptions.handle(request, msg)
if base.is_service_enabled(request, 'volume'):
if cinder.is_volume_service_enabled(request):
try:
limits.update(cinder.tenant_absolute_limits(request))
volumes = cinder.volume_list(request)