Merge "Allow horizon to function without nova"
This commit is contained in:
commit
4aa405bc08
@ -27,18 +27,24 @@ from openstack_dashboard.api import nova
|
||||
class NetworkClient(object):
|
||||
def __init__(self, request):
|
||||
neutron_enabled = base.is_service_enabled(request, 'network')
|
||||
nova_enabled = base.is_service_enabled(request, 'compute')
|
||||
|
||||
self.secgroups, self.floating_ips = None, None
|
||||
if neutron_enabled:
|
||||
self.floating_ips = neutron.FloatingIpManager(request)
|
||||
else:
|
||||
elif nova_enabled:
|
||||
self.floating_ips = nova.FloatingIpManager(request)
|
||||
|
||||
if (neutron_enabled and
|
||||
neutron.is_extension_supported(request, 'security-group')):
|
||||
self.secgroups = neutron.SecurityGroupManager(request)
|
||||
else:
|
||||
elif nova_enabled:
|
||||
self.secgroups = nova.SecurityGroupManager(request)
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self.floating_ips is not None
|
||||
|
||||
|
||||
def floating_ip_pools_list(request):
|
||||
return NetworkClient(request).floating_ips.list_pools()
|
||||
@ -88,7 +94,8 @@ def floating_ip_simple_associate_supported(request):
|
||||
|
||||
|
||||
def floating_ip_supported(request):
|
||||
return NetworkClient(request).floating_ips.is_supported()
|
||||
nwc = NetworkClient(request)
|
||||
return nwc.enabled and nwc.floating_ips.is_supported()
|
||||
|
||||
|
||||
def security_group_list(request):
|
||||
|
@ -16,6 +16,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
|
||||
class QuotaFilterAction(tables.FilterAction):
|
||||
def filter(self, table, tenants, filter_string):
|
||||
@ -36,6 +38,9 @@ class UpdateDefaultQuotas(tables.LinkAction):
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
|
||||
def allowed(self, request, _=None):
|
||||
return quotas.enabled_quotas(request)
|
||||
|
||||
|
||||
def get_quota_name(quota):
|
||||
QUOTA_NAMES = {
|
||||
|
@ -46,7 +46,9 @@ class ServicesViewTests(test.BaseAdminViewTests):
|
||||
self.mox.StubOutWithMock(api.neutron, 'is_extension_supported')
|
||||
|
||||
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
|
||||
.AndReturn(True)
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.MultipleTimes().AndReturn(neutron_enabled)
|
||||
|
||||
@ -57,7 +59,7 @@ class ServicesViewTests(test.BaseAdminViewTests):
|
||||
if neutron_enabled:
|
||||
api.neutron.is_extension_supported(
|
||||
IsA(http.HttpRequest),
|
||||
'security-group').AndReturn(neutron_sg_enabled)
|
||||
'security-group').MultipleTimes().AndReturn(neutron_sg_enabled)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
|
@ -24,6 +24,7 @@ class MetadataDefinitions(horizon.Panel):
|
||||
name = _("Metadata Definitions")
|
||||
slug = 'metadata_defs'
|
||||
policy_rules = (("image", "get_metadef_namespaces"),)
|
||||
permissions = ('openstack.services.image',)
|
||||
|
||||
@staticmethod
|
||||
def can_register():
|
||||
|
@ -27,6 +27,7 @@ class Overview(horizon.Panel):
|
||||
name = _("Overview")
|
||||
slug = 'overview'
|
||||
policy_rules = (('identity', 'identity:list_projects'),)
|
||||
permissions = ('openstack.services.compute',)
|
||||
|
||||
|
||||
dashboard.Admin.register(Overview)
|
||||
|
@ -24,6 +24,7 @@ from keystoneclient.exceptions import Conflict # noqa
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard import policy
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
|
||||
class RescopeTokenToProject(tables.LinkAction):
|
||||
@ -103,7 +104,8 @@ class UsageLink(tables.LinkAction):
|
||||
policy_rules = (("compute", "compute_extension:simple_tenant_usage:show"),)
|
||||
|
||||
def allowed(self, request, project):
|
||||
return request.user.is_superuser
|
||||
return (request.user.is_superuser and
|
||||
api.base.is_service_enabled(request, 'compute'))
|
||||
|
||||
|
||||
class CreateProject(tables.LinkAction):
|
||||
@ -153,7 +155,8 @@ class ModifyQuotas(tables.LinkAction):
|
||||
if api.keystone.VERSIONS.active < 3:
|
||||
return True
|
||||
else:
|
||||
return api.keystone.is_cloud_admin(request)
|
||||
return (api.keystone.is_cloud_admin(request) and
|
||||
quotas.enabled_quotas(request))
|
||||
|
||||
def get_link_url(self, project):
|
||||
step = 'update_quotas'
|
||||
|
@ -53,7 +53,8 @@ PROJECT_DETAIL_URL = reverse('horizon:identity:projects:detail', args=[1])
|
||||
class TenantsViewTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.keystone: ('domain_get',
|
||||
'tenant_list',
|
||||
'domain_lookup')})
|
||||
'domain_lookup'),
|
||||
quotas: ('enabled_quotas',)})
|
||||
def test_index(self):
|
||||
domain = self.domains.get(id="1")
|
||||
api.keystone.domain_get(IsA(http.HttpRequest), '1').AndReturn(domain)
|
||||
@ -64,6 +65,8 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
||||
.AndReturn([self.tenants.list(), False])
|
||||
api.keystone.domain_lookup(IgnoreArg()).AndReturn({domain.id:
|
||||
domain.name})
|
||||
quotas.enabled_quotas(IsA(http.HttpRequest)).MultipleTimes()\
|
||||
.AndReturn(('instances',))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
@ -72,7 +75,8 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
||||
|
||||
@test.create_stubs({api.keystone: ('tenant_list',
|
||||
'get_effective_domain_id',
|
||||
'domain_lookup')})
|
||||
'domain_lookup'),
|
||||
quotas: ('enabled_quotas',)})
|
||||
def test_index_with_domain_context(self):
|
||||
domain = self.domains.get(id="1")
|
||||
|
||||
@ -91,6 +95,7 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
||||
.AndReturn([domain_tenants, False])
|
||||
api.keystone.domain_lookup(IgnoreArg()).AndReturn({domain.id:
|
||||
domain.name})
|
||||
quotas.enabled_quotas(IsA(http.HttpRequest)).AndReturn(('instances',))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
@ -201,6 +206,8 @@ 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), 'compute') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.cinder.is_volume_service_enabled(IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
@ -1607,12 +1614,14 @@ class UsageViewTests(test.BaseAdminViewTests):
|
||||
|
||||
|
||||
class DetailProjectViewTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.keystone: ('tenant_get',)})
|
||||
@test.create_stubs({api.keystone: ('tenant_get',),
|
||||
quotas: ('enabled_quotas',)})
|
||||
def test_detail_view(self):
|
||||
project = self.tenants.first()
|
||||
|
||||
api.keystone.tenant_get(IsA(http.HttpRequest), self.tenant.id) \
|
||||
.AndReturn(project)
|
||||
quotas.enabled_quotas(IsA(http.HttpRequest)).AndReturn(('instances',))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(PROJECT_DETAIL_URL, args=[project.id])
|
||||
|
@ -386,9 +386,12 @@ class UpdateProjectGroups(workflows.UpdateMembersStep):
|
||||
class CommonQuotaWorkflow(workflows.Workflow):
|
||||
def _update_project_quota(self, request, data, project_id):
|
||||
disabled_quotas = quotas.get_disabled_quotas(request)
|
||||
nova_data = {key: data[key] for key in
|
||||
set(quotas.NOVA_QUOTA_FIELDS) - disabled_quotas}
|
||||
nova.tenant_quota_update(request, project_id, **nova_data)
|
||||
|
||||
# Update the project quotas.
|
||||
if api.base.is_service_enabled(request, 'compute'):
|
||||
nova_data = {key: data[key] for key in
|
||||
set(quotas.NOVA_QUOTA_FIELDS) - disabled_quotas}
|
||||
nova.tenant_quota_update(request, project_id, **nova_data)
|
||||
|
||||
if cinder.is_volume_service_enabled(request):
|
||||
cinder_data = dict([(key, data[key]) for key in
|
||||
|
@ -374,6 +374,8 @@ class FloatingIpNeutronViewTests(FloatingIpViewTests):
|
||||
.AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndReturn(self.quotas.first())
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -435,6 +437,8 @@ class FloatingIpNeutronViewTests(FloatingIpViewTests):
|
||||
.AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndReturn(self.quotas.first())
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
|
@ -51,6 +51,8 @@ class LaunchImage(tables.LinkAction):
|
||||
return "?".join([base_url, params])
|
||||
|
||||
def allowed(self, request, image=None):
|
||||
if not api.base.is_service_enabled(request, 'compute'):
|
||||
return False
|
||||
if image and image.container_format not in NOT_LAUNCHABLE_FORMATS:
|
||||
return image.status in ("active",)
|
||||
return False
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
|
||||
@ -49,8 +50,10 @@ def get_context(request, context=None):
|
||||
_has_permission(request, (("network", "create_router"),)))
|
||||
context['router_quota_exceeded'] = _quota_exceeded(request, 'routers')
|
||||
context['console_type'] = getattr(settings, 'CONSOLE_TYPE', 'AUTO')
|
||||
context['show_ng_launch'] = getattr(
|
||||
settings, 'LAUNCH_INSTANCE_NG_ENABLED', True)
|
||||
context['show_legacy_launch'] = getattr(
|
||||
settings, 'LAUNCH_INSTANCE_LEGACY_ENABLED', False)
|
||||
context['show_ng_launch'] = (
|
||||
base.is_service_enabled(request, 'compute') and
|
||||
getattr(settings, 'LAUNCH_INSTANCE_NG_ENABLED', True))
|
||||
context['show_legacy_launch'] = (
|
||||
base.is_service_enabled(request, 'compute') and
|
||||
getattr(settings, 'LAUNCH_INSTANCE_LEGACY_ENABLED', False))
|
||||
return context
|
||||
|
@ -24,3 +24,4 @@ import horizon
|
||||
class Overview(horizon.Panel):
|
||||
name = _("Overview")
|
||||
slug = 'overview'
|
||||
permissions = ('openstack.services.compute',)
|
||||
|
@ -58,6 +58,8 @@ class LaunchVolume(tables.LinkAction):
|
||||
return "?".join([base_url, params])
|
||||
|
||||
def allowed(self, request, volume=None):
|
||||
if not api.base.is_service_enabled(request, 'compute'):
|
||||
return False
|
||||
if getattr(volume, 'bootable', '') == 'true':
|
||||
return volume.status == "available"
|
||||
return False
|
||||
@ -179,6 +181,9 @@ class EditAttachments(tables.LinkAction):
|
||||
icon = "pencil"
|
||||
|
||||
def allowed(self, request, volume=None):
|
||||
if not api.base.is_service_enabled(request, 'compute'):
|
||||
return False
|
||||
|
||||
if volume:
|
||||
project_id = getattr(volume, "os-vol-tenant-attr:tenant_id", None)
|
||||
attach_allowed = \
|
||||
|
@ -32,6 +32,8 @@ class NetworkClientTestCase(test.APITestCase):
|
||||
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
nc = api.network.NetworkClient(self.request)
|
||||
@ -42,6 +44,8 @@ class NetworkClientTestCase(test.APITestCase):
|
||||
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
self.neutronclient = self.stub_neutronclient()
|
||||
self.neutronclient.list_extensions() \
|
||||
.AndReturn({'extensions': self.api_extensions.list()})
|
||||
@ -55,6 +59,8 @@ class NetworkClientTestCase(test.APITestCase):
|
||||
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
self.neutronclient = self.stub_neutronclient()
|
||||
self.neutronclient.list_extensions().AndReturn({'extensions': []})
|
||||
self.mox.ReplayAll()
|
||||
@ -70,6 +76,8 @@ class NetworkApiNovaTestBase(test.APITestCase):
|
||||
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
|
||||
.AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
|
||||
|
||||
class NetworkApiNovaSecurityGroupTests(NetworkApiNovaTestBase):
|
||||
@ -339,6 +347,8 @@ class NetworkApiNeutronSecurityGroupTests(NetworkApiNeutronTestBase):
|
||||
super(NetworkApiNeutronSecurityGroupTests, self).setUp()
|
||||
self.qclient.list_extensions() \
|
||||
.AndReturn({'extensions': self.api_extensions.list()})
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
self.sg_dict = dict([(sg['id'], sg['name']) for sg
|
||||
in self.api_q_secgroups.list()])
|
||||
|
||||
@ -521,6 +531,8 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
|
||||
super(NetworkApiNeutronFloatingIpTests, self).setUp()
|
||||
self.qclient.list_extensions() \
|
||||
.AndReturn({'extensions': self.api_extensions.list()})
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \
|
||||
.AndReturn(True)
|
||||
|
||||
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_router': True})
|
||||
def test_floating_ip_supported(self):
|
||||
|
@ -33,26 +33,36 @@ from openstack_dashboard.usage import quotas
|
||||
|
||||
class QuotaTests(test.APITestCase):
|
||||
|
||||
def get_usages(self, with_volume=True, nova_quotas_enabled=True):
|
||||
if nova_quotas_enabled:
|
||||
usages = {'injected_file_content_bytes': {'quota': 1},
|
||||
'metadata_items': {'quota': 1},
|
||||
'injected_files': {'quota': 1},
|
||||
'security_groups': {'quota': 10},
|
||||
'security_group_rules': {'quota': 20},
|
||||
'fixed_ips': {'quota': 10},
|
||||
'ram': {'available': 8976, 'used': 1024, 'quota': 10000},
|
||||
'floating_ips': {'available': 0, 'used': 2, 'quota': 1},
|
||||
'instances': {'available': 8, 'used': 2, 'quota': 10},
|
||||
'cores': {'available': 8, 'used': 2, 'quota': 10}}
|
||||
else:
|
||||
inf = float('inf')
|
||||
usages = {'security_groups': {'available': inf, 'quota': inf},
|
||||
'ram': {'available': inf, 'used': 1024, 'quota': inf},
|
||||
'floating_ips': {
|
||||
'available': inf, 'used': 2, 'quota': inf},
|
||||
'instances': {'available': inf, 'used': 2, 'quota': inf},
|
||||
'cores': {'available': inf, 'used': 2, 'quota': inf}}
|
||||
def get_usages(self, with_volume=True, with_compute=True,
|
||||
nova_quotas_enabled=True):
|
||||
usages = {}
|
||||
if with_compute:
|
||||
# These are all nova fields; the neutron ones are named slightly
|
||||
# differently and aren't included in here yet
|
||||
if nova_quotas_enabled:
|
||||
usages.update({
|
||||
'injected_file_content_bytes': {'quota': 1},
|
||||
'metadata_items': {'quota': 1},
|
||||
'injected_files': {'quota': 1},
|
||||
'security_groups': {'quota': 10},
|
||||
'security_group_rules': {'quota': 20},
|
||||
'fixed_ips': {'quota': 10},
|
||||
'ram': {'available': 8976, 'used': 1024, 'quota': 10000},
|
||||
'floating_ips': {'available': 0, 'used': 2, 'quota': 1},
|
||||
'instances': {'available': 8, 'used': 2, 'quota': 10},
|
||||
'cores': {'available': 8, 'used': 2, 'quota': 10}
|
||||
})
|
||||
else:
|
||||
inf = float('inf')
|
||||
usages.update({
|
||||
'security_groups': {'available': inf, 'quota': inf},
|
||||
'ram': {'available': inf, 'used': 1024, 'quota': inf},
|
||||
'floating_ips': {'available': inf, 'used': 2,
|
||||
'quota': inf},
|
||||
'instances': {'available': inf, 'used': 2, 'quota': inf},
|
||||
'cores': {'available': inf, 'used': 2, 'quota': inf}
|
||||
})
|
||||
|
||||
if with_volume:
|
||||
usages.update({'volumes': {'available': 0, 'used': 4, 'quota': 1},
|
||||
'snapshots': {'available': 0, 'used': 3,
|
||||
@ -78,26 +88,34 @@ class QuotaTests(test.APITestCase):
|
||||
'tenant_quota_get',
|
||||
'is_volume_service_enabled')})
|
||||
def _test_tenant_quota_usages(self, nova_quotas_enabled=True,
|
||||
with_volume=True):
|
||||
servers = [s for s in self.servers.list()
|
||||
if s.tenant_id == self.request.user.tenant_id]
|
||||
with_compute=True, with_volume=True):
|
||||
|
||||
cinder.is_volume_service_enabled(IsA(http.HttpRequest)).AndReturn(
|
||||
with_volume)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndReturn(self.quotas.first())
|
||||
api.network.floating_ip_supported(IsA(http.HttpRequest)) \
|
||||
.AndReturn(True)
|
||||
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.floating_ips.list())
|
||||
search_opts = {'tenant_id': self.request.user.tenant_id}
|
||||
api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts,
|
||||
all_tenants=True) \
|
||||
.AndReturn([servers, False])
|
||||
api.base.is_service_enabled(
|
||||
IsA(http.HttpRequest), 'compute'
|
||||
).MultipleTimes().AndReturn(with_compute)
|
||||
if with_compute:
|
||||
servers = [s for s in self.servers.list()
|
||||
if s.tenant_id == self.request.user.tenant_id]
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.network.floating_ip_supported(IsA(http.HttpRequest)) \
|
||||
.AndReturn(True)
|
||||
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.floating_ips.list())
|
||||
search_opts = {'tenant_id': self.request.user.tenant_id}
|
||||
api.nova.server_list(IsA(http.HttpRequest),
|
||||
search_opts=search_opts,
|
||||
all_tenants=True) \
|
||||
.AndReturn([servers, False])
|
||||
|
||||
if nova_quotas_enabled:
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndReturn(self.quotas.first())
|
||||
|
||||
if with_volume:
|
||||
opts = {'all_tenants': 1,
|
||||
'project_id': self.request.user.tenant_id}
|
||||
@ -112,7 +130,8 @@ class QuotaTests(test.APITestCase):
|
||||
|
||||
quota_usages = quotas.tenant_quota_usages(self.request)
|
||||
expected_output = self.get_usages(
|
||||
nova_quotas_enabled=nova_quotas_enabled, with_volume=with_volume)
|
||||
nova_quotas_enabled=nova_quotas_enabled, with_volume=with_volume,
|
||||
with_compute=with_compute)
|
||||
|
||||
# Compare internal structure of usages to expected.
|
||||
self.assertItemsEqual(expected_output, quota_usages.usages)
|
||||
@ -125,6 +144,7 @@ class QuotaTests(test.APITestCase):
|
||||
@override_settings(OPENSTACK_HYPERVISOR_FEATURES={'enable_quotas': False})
|
||||
def test_tenant_quota_usages_wo_nova_quotas(self):
|
||||
self._test_tenant_quota_usages(nova_quotas_enabled=False,
|
||||
with_compute=True,
|
||||
with_volume=False)
|
||||
|
||||
@override_settings(OPENSTACK_HYPERVISOR_FEATURES={'enable_quotas': False})
|
||||
@ -135,11 +155,15 @@ class QuotaTests(test.APITestCase):
|
||||
False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
# Nova enabled but quotas disabled
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').AndReturn(True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
result_quotas = quotas.get_disabled_quotas(self.request)
|
||||
expected_quotas = list(quotas.CINDER_QUOTA_FIELDS) + \
|
||||
list(quotas.NEUTRON_QUOTA_FIELDS) + list(quotas.NOVA_QUOTA_FIELDS)
|
||||
list(quotas.NEUTRON_QUOTA_FIELDS) + \
|
||||
list(quotas.NOVA_QUOTA_FIELDS) + list(quotas.MISSING_QUOTA_FIELDS)
|
||||
self.assertItemsEqual(result_quotas, expected_quotas)
|
||||
|
||||
@test.create_stubs({api.nova: ('server_list',
|
||||
@ -158,6 +182,8 @@ class QuotaTests(test.APITestCase):
|
||||
).AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
@ -197,6 +223,8 @@ class QuotaTests(test.APITestCase):
|
||||
).AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
@ -244,6 +272,8 @@ class QuotaTests(test.APITestCase):
|
||||
).AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
@ -293,6 +323,8 @@ class QuotaTests(test.APITestCase):
|
||||
).AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
@ -332,8 +364,7 @@ class QuotaTests(test.APITestCase):
|
||||
|
||||
quotas._get_tenant_volume_usages(self.request, {}, [], None)
|
||||
|
||||
@test.create_stubs({api.nova: ('tenant_quota_get',),
|
||||
api.base: ('is_service_enabled',),
|
||||
@test.create_stubs({api.base: ('is_service_enabled',),
|
||||
api.cinder: ('tenant_quota_get',
|
||||
'is_volume_service_enabled'),
|
||||
exceptions: ('handle',)})
|
||||
@ -343,8 +374,8 @@ class QuotaTests(test.APITestCase):
|
||||
).AndReturn(True)
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'network').AndReturn(False)
|
||||
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndReturn(self.quotas.first())
|
||||
api.base.is_service_enabled(IsA(http.HttpRequest),
|
||||
'compute').AndReturn(False)
|
||||
api.cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \
|
||||
.AndRaise(cinder.cinder_exception.ClientException('test'))
|
||||
exceptions.handle(IsA(http.HttpRequest),
|
||||
@ -353,17 +384,16 @@ class QuotaTests(test.APITestCase):
|
||||
|
||||
quotas._get_quota_data(self.request, 'tenant_quota_get')
|
||||
|
||||
@test.create_stubs({api.nova: ('tenant_absolute_limits',),
|
||||
api.base: ('is_service_enabled',),
|
||||
@test.create_stubs({api.base: ('is_service_enabled',),
|
||||
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),
|
||||
'compute').AndReturn(False)
|
||||
api.cinder.is_volume_service_enabled(
|
||||
IsA(http.HttpRequest)
|
||||
).AndReturn(True)
|
||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest),
|
||||
reserved=True).AndReturn({})
|
||||
api.cinder.tenant_absolute_limits(IsA(http.HttpRequest)) \
|
||||
.AndRaise(cinder.cinder_exception.ClientException('test'))
|
||||
exceptions.handle(IsA(http.HttpRequest),
|
||||
|
@ -141,10 +141,14 @@ def _get_quota_data(request, method_name, disabled_quotas=None,
|
||||
quotasets = []
|
||||
if not tenant_id:
|
||||
tenant_id = request.user.tenant_id
|
||||
quotasets.append(getattr(nova, method_name)(request, tenant_id))
|
||||
qs = base.QuotaSet()
|
||||
if disabled_quotas is None:
|
||||
disabled_quotas = get_disabled_quotas(request)
|
||||
|
||||
qs = base.QuotaSet()
|
||||
|
||||
if 'instances' not in disabled_quotas:
|
||||
quotasets.append(getattr(nova, method_name)(request, tenant_id))
|
||||
|
||||
if 'volumes' not in disabled_quotas:
|
||||
try:
|
||||
quotasets.append(getattr(cinder, method_name)(request, tenant_id))
|
||||
@ -231,10 +235,6 @@ def get_tenant_quota_data(request, disabled_quotas=None, tenant_id=None):
|
||||
def get_disabled_quotas(request):
|
||||
disabled_quotas = set([])
|
||||
|
||||
# Nova
|
||||
if not nova.can_set_quotas():
|
||||
disabled_quotas.update(NOVA_QUOTA_FIELDS)
|
||||
|
||||
# Cinder
|
||||
if not cinder.is_volume_service_enabled(request):
|
||||
disabled_quotas.update(CINDER_QUOTA_FIELDS)
|
||||
@ -260,10 +260,25 @@ def get_disabled_quotas(request):
|
||||
LOG.exception("There was an error checking if the Neutron "
|
||||
"quotas extension is enabled.")
|
||||
|
||||
# Nova
|
||||
if not (base.is_service_enabled(request, 'compute') and
|
||||
nova.can_set_quotas()):
|
||||
disabled_quotas.update(NOVA_QUOTA_FIELDS)
|
||||
# The 'missing' quota fields are all nova (this is hardcoded in
|
||||
# dashboards.admin.defaults.workflows)
|
||||
disabled_quotas.update(MISSING_QUOTA_FIELDS)
|
||||
|
||||
# There appear to be no glance quota fields currently
|
||||
return disabled_quotas
|
||||
|
||||
|
||||
def _get_tenant_compute_usages(request, usages, disabled_quotas, tenant_id):
|
||||
# Unlike the other services it can be the case that nova is enabled but
|
||||
# doesn't support quotas, in which case we still want to get usage info,
|
||||
# so don't rely on '"instances" in disabled_quotas' as elsewhere
|
||||
if not base.is_service_enabled(request, 'compute'):
|
||||
return
|
||||
|
||||
if tenant_id:
|
||||
# determine if the user has permission to view across projects
|
||||
# there are cases where an administrator wants to check the quotas
|
||||
@ -396,7 +411,8 @@ def tenant_limit_usages(request):
|
||||
limits = {}
|
||||
|
||||
try:
|
||||
limits.update(nova.tenant_absolute_limits(request, reserved=True))
|
||||
if base.is_service_enabled(request, 'compute'):
|
||||
limits.update(nova.tenant_absolute_limits(request, reserved=True))
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve compute limit information.")
|
||||
exceptions.handle(request, msg)
|
||||
@ -419,3 +435,8 @@ def tenant_limit_usages(request):
|
||||
exceptions.handle(request, msg)
|
||||
|
||||
return limits
|
||||
|
||||
|
||||
def enabled_quotas(request):
|
||||
"""Returns the list of quotas available minus those that are disabled"""
|
||||
return set(QUOTA_FIELDS) - get_disabled_quotas(request)
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
prelude: >
|
||||
Horizon no longer requires Nova (or Glance) to function;
|
||||
it will run as long as keystone is present (for instance,
|
||||
swift-only deployments).
|
||||
features:
|
||||
Nova and Glance are no longer required in order to run
|
||||
Horizon. As long as keystone is present, Horizon will
|
||||
run correctly.
|
Loading…
Reference in New Issue
Block a user