diff --git a/horizon/exceptions.py b/horizon/exceptions.py index 9c7879f7ae..de2b72e282 100644 --- a/horizon/exceptions.py +++ b/horizon/exceptions.py @@ -197,7 +197,7 @@ class HandledException(HorizonException): UNAUTHORIZED = tuple(HORIZON_CONFIG['exceptions']['unauthorized']) NOT_FOUND = tuple(HORIZON_CONFIG['exceptions']['not_found']) -RECOVERABLE = (AlreadyExists, Conflict, NotAvailable) +RECOVERABLE = (AlreadyExists, Conflict, NotAvailable, ServiceCatalogException) RECOVERABLE += tuple(HORIZON_CONFIG['exceptions']['recoverable']) diff --git a/horizon/tabs/base.py b/horizon/tabs/base.py index e9195a5613..4599641c38 100644 --- a/horizon/tabs/base.py +++ b/horizon/tabs/base.py @@ -238,11 +238,17 @@ class Tab(html.HTMLElement): Read-only access to determine whether or not this tab's data should be loaded immediately. + + .. attribute:: permissions + + A list of permission names which this tab requires in order to be + displayed. Defaults to an empty list (``[]``). """ name = None slug = None preload = True _active = None + permissions = [] def __init__(self, tab_group, request=None): super(Tab, self).__init__() @@ -255,12 +261,16 @@ class Tab(html.HTMLElement): self.tab_group = tab_group self.request = request if request: - self._allowed = self.allowed(request) + self._allowed = self.allowed(request) and ( + self._has_permissions(request)) self._enabled = self.enabled(request) def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.slug) + def _has_permissions(self, request): + return request.user.has_perms(self.permissions) + def is_active(self): """Method to access whether or not this tab is the active tab.""" if self._active is None: diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py index bb54045d83..2c2963753a 100644 --- a/openstack_dashboard/api/cinder.py +++ b/openstack_dashboard/api/cinder.py @@ -130,7 +130,7 @@ def cinderclient(request): cinder_url = base.url_for(request, 'volume') except exceptions.ServiceCatalogException: LOG.debug('no volume service configured.') - return None + raise LOG.debug('cinderclient connection created using token "%s" and url "%s"' % (request.user.token.id, cinder_url)) c = api_version['client'].Client(request.user.username, diff --git a/openstack_dashboard/dashboards/admin/aggregates/panel.py b/openstack_dashboard/dashboards/admin/aggregates/panel.py index e6e7c42aab..2477295e4c 100644 --- a/openstack_dashboard/dashboards/admin/aggregates/panel.py +++ b/openstack_dashboard/dashboards/admin/aggregates/panel.py @@ -20,6 +20,7 @@ from openstack_dashboard.dashboards.admin import dashboard class Aggregates(horizon.Panel): name = _("Host Aggregates") slug = 'aggregates' + permissions = ('openstack.services.compute',) dashboard.Admin.register(Aggregates) diff --git a/openstack_dashboard/dashboards/admin/flavors/panel.py b/openstack_dashboard/dashboards/admin/flavors/panel.py index d13248fe3f..b2d0e4e8d7 100644 --- a/openstack_dashboard/dashboards/admin/flavors/panel.py +++ b/openstack_dashboard/dashboards/admin/flavors/panel.py @@ -26,6 +26,7 @@ from openstack_dashboard.dashboards.admin import dashboard class Flavors(horizon.Panel): name = _("Flavors") slug = 'flavors' + permissions = ('openstack.services.compute',) dashboard.Admin.register(Flavors) diff --git a/openstack_dashboard/dashboards/admin/hypervisors/panel.py b/openstack_dashboard/dashboards/admin/hypervisors/panel.py index c47a7d0c1e..7e5d27533c 100644 --- a/openstack_dashboard/dashboards/admin/hypervisors/panel.py +++ b/openstack_dashboard/dashboards/admin/hypervisors/panel.py @@ -21,7 +21,7 @@ from openstack_dashboard.dashboards.admin import dashboard class Hypervisors(horizon.Panel): name = _("Hypervisors") slug = 'hypervisors' - permissions = ('openstack.roles.admin',) + permissions = ('openstack.roles.admin', 'openstack.services.compute') dashboard.Admin.register(Hypervisors) diff --git a/openstack_dashboard/dashboards/admin/images/panel.py b/openstack_dashboard/dashboards/admin/images/panel.py index 2b525f6f0a..5983aa6a4c 100644 --- a/openstack_dashboard/dashboards/admin/images/panel.py +++ b/openstack_dashboard/dashboards/admin/images/panel.py @@ -26,6 +26,7 @@ from openstack_dashboard.dashboards.admin import dashboard class Images(horizon.Panel): name = _("Images") slug = 'images' + permissions = ('openstack.services.image',) dashboard.Admin.register(Images) diff --git a/openstack_dashboard/dashboards/admin/info/tabs.py b/openstack_dashboard/dashboards/admin/info/tabs.py index 397bea69d8..9bcd25824e 100644 --- a/openstack_dashboard/dashboards/admin/info/tabs.py +++ b/openstack_dashboard/dashboards/admin/info/tabs.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from django.conf import settings from django.utils.translation import ugettext_lazy as _ from horizon import exceptions @@ -49,6 +50,7 @@ class NovaServicesTab(tabs.TableTab): name = _("Compute Services") slug = "nova_services" template_name = constants.INFO_DETAIL_TEMPLATE_NAME + permissions = ('openstack.services.compute',) def get_nova_services_data(self): try: @@ -56,8 +58,8 @@ class NovaServicesTab(tabs.TableTab): except Exception: msg = _('Unable to get nova services list.') exceptions.check_message(["Connection", "refused"], msg) - raise - + exceptions.handle(self.request, msg) + services = [] return services @@ -66,6 +68,7 @@ class CinderServicesTab(tabs.TableTab): name = _("Block Storage Services") slug = "cinder_services" template_name = constants.INFO_DETAIL_TEMPLATE_NAME + permissions = ('openstack.services.volume',) def get_cinder_services_data(self): try: @@ -73,8 +76,8 @@ class CinderServicesTab(tabs.TableTab): except Exception: msg = _('Unable to get cinder services list.') exceptions.check_message(["Connection", "refused"], msg) - raise - + exceptions.handle(self.request, msg) + services = [] return services @@ -85,8 +88,12 @@ class NetworkAgentsTab(tabs.TableTab): template_name = constants.INFO_DETAIL_TEMPLATE_NAME def allowed(self, request): - return (base.is_service_enabled(request, 'network') and - neutron.is_agent_extension_supported(request)) + try: + return (base.is_service_enabled(request, 'network') and + neutron.is_agent_extension_supported(request)) + except Exception: + exceptions.handle(request, _('Unable to get network agents info.')) + return False def get_network_agents_data(self): try: @@ -94,8 +101,8 @@ class NetworkAgentsTab(tabs.TableTab): except Exception: msg = _('Unable to get network agents list.') exceptions.check_message(["Connection", "refused"], msg) - raise - + exceptions.handle(self.request, msg) + agents = [] return agents @@ -104,6 +111,7 @@ class DefaultQuotasTab(tabs.TableTab): name = _("Default Quotas") slug = "quotas" template_name = constants.INFO_DETAIL_TEMPLATE_NAME + permissions = ('openstack.services.compute',) def get_quotas_data(self): request = self.tab_group.request diff --git a/openstack_dashboard/dashboards/admin/instances/panel.py b/openstack_dashboard/dashboards/admin/instances/panel.py index 3dcb1bce63..39a0047a7a 100644 --- a/openstack_dashboard/dashboards/admin/instances/panel.py +++ b/openstack_dashboard/dashboards/admin/instances/panel.py @@ -26,7 +26,7 @@ from openstack_dashboard.dashboards.admin import dashboard class Instances(horizon.Panel): name = _("Instances") slug = 'instances' - permissions = ('openstack.roles.admin',) + permissions = ('openstack.roles.admin', 'openstack.services.compute') dashboard.Admin.register(Instances) diff --git a/openstack_dashboard/dashboards/project/access_and_security/tabs.py b/openstack_dashboard/dashboards/project/access_and_security/tabs.py index 06e19a4a8c..00948460c2 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/tabs.py +++ b/openstack_dashboard/dashboards/project/access_and_security/tabs.py @@ -42,6 +42,7 @@ class SecurityGroupsTab(tabs.TableTab): name = _("Security Groups") slug = "security_groups_tab" template_name = "horizon/common/_detail_table.html" + permissions = ('openstack.services.compute',) def get_security_groups_data(self): try: @@ -58,6 +59,7 @@ class KeypairsTab(tabs.TableTab): name = _("Key Pairs") slug = "keypairs_tab" template_name = "horizon/common/_detail_table.html" + permissions = ('openstack.services.compute',) def get_keypairs_data(self): try: @@ -74,6 +76,7 @@ class FloatingIPsTab(tabs.TableTab): name = _("Floating IPs") slug = "floating_ips_tab" template_name = "horizon/common/_detail_table.html" + permissions = ('openstack.services.compute',) def get_floating_ips_data(self): try: diff --git a/openstack_dashboard/dashboards/project/images/panel.py b/openstack_dashboard/dashboards/project/images/panel.py index bf5bf41e3c..7203f506d3 100644 --- a/openstack_dashboard/dashboards/project/images/panel.py +++ b/openstack_dashboard/dashboards/project/images/panel.py @@ -23,6 +23,7 @@ from openstack_dashboard.dashboards.project import dashboard class Images(horizon.Panel): name = _("Images") slug = 'images' + permissions = ('openstack.services.image',) dashboard.Project.register(Images) diff --git a/openstack_dashboard/dashboards/project/instances/panel.py b/openstack_dashboard/dashboards/project/instances/panel.py index a590950703..acade3c519 100644 --- a/openstack_dashboard/dashboards/project/instances/panel.py +++ b/openstack_dashboard/dashboards/project/instances/panel.py @@ -22,6 +22,7 @@ from openstack_dashboard.dashboards.project import dashboard class Instances(horizon.Panel): name = _("Instances") slug = 'instances' + permissions = ('openstack.services.compute',) dashboard.Project.register(Instances) diff --git a/openstack_dashboard/exceptions.py b/openstack_dashboard/exceptions.py index 89e7ceb59c..02177f1948 100644 --- a/openstack_dashboard/exceptions.py +++ b/openstack_dashboard/exceptions.py @@ -22,6 +22,7 @@ from heatclient import exc as heatclient from keystoneclient import exceptions as keystoneclient from neutronclient.common import exceptions as neutronclient from novaclient import exceptions as novaclient +from requests import exceptions as requests from saharaclient.api import base as saharaclient from swiftclient import client as swiftclient from troveclient import exceptions as troveclient @@ -76,4 +77,5 @@ RECOVERABLE = ( heatclient.HTTPException, troveclient.ClientException, saharaclient.APIException, + requests.RequestException, ) diff --git a/openstack_dashboard/usage/views.py b/openstack_dashboard/usage/views.py index 6d04753a8c..fe6ff8ff73 100644 --- a/openstack_dashboard/usage/views.py +++ b/openstack_dashboard/usage/views.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +from django.utils.translation import ugettext_lazy as _ +from horizon import exceptions from horizon import tables from openstack_dashboard import api from openstack_dashboard.usage import base @@ -38,20 +40,29 @@ class UsageView(tables.DataTableView): return "text/html" def get_data(self): - project_id = self.kwargs.get('project_id', self.request.user.tenant_id) - self.usage = self.usage_class(self.request, project_id) - self.usage.summarize(*self.usage.get_date_range()) - self.usage.get_limits() - self.kwargs['usage'] = self.usage - return self.usage.usage_list + try: + project_id = self.kwargs.get('project_id', + self.request.user.tenant_id) + self.usage = self.usage_class(self.request, project_id) + self.usage.summarize(*self.usage.get_date_range()) + self.usage.get_limits() + self.kwargs['usage'] = self.usage + return self.usage.usage_list + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve usage information.')) + return [] def get_context_data(self, **kwargs): context = super(UsageView, self).get_context_data(**kwargs) context['table'].kwargs['usage'] = self.usage context['form'] = self.usage.form context['usage'] = self.usage - context['simple_tenant_usage_enabled'] = \ - api.nova.extension_supported('SimpleTenantUsage', self.request) + try: + context['simple_tenant_usage_enabled'] = \ + api.nova.extension_supported('SimpleTenantUsage', self.request) + except Exception: + context['simple_tenant_usage_enabled'] = True return context def render_to_response(self, context, **response_kwargs):