Make API Access a panel under compute

This patch moves the API Access view, from a tab on the Access
& Security panel to its own panel under the Compute panel group

Change-Id: I1e523ba2e7e959474c0fc77f8b6c42994a481081
Implements: blueprint reorganise-access-and-security
This commit is contained in:
Rob Cresswell 2017-01-25 11:21:24 +00:00 committed by Richard Jones
parent 94a47461c0
commit 6b2b22631b
23 changed files with 92 additions and 113 deletions

View File

@ -257,10 +257,6 @@ class FloatingIpViewTests(test.TestCase):
IsA(http.HttpRequest),
'network').MultipleTimes() \
.AndReturn(True)
api.base.is_service_enabled(
IsA(http.HttpRequest),
'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()
@ -314,10 +310,6 @@ class FloatingIpViewTests(test.TestCase):
IsA(http.HttpRequest),
'network').MultipleTimes() \
.AndReturn(True)
api.base.is_service_enabled(
IsA(http.HttpRequest),
'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()

View File

@ -24,12 +24,9 @@ from horizon import tabs
from neutronclient.common import exceptions as neutron_exc
from openstack_dashboard.api import keystone
from openstack_dashboard.api import network
from openstack_dashboard.api import nova
from openstack_dashboard.dashboards.project.access_and_security.\
api_access.tables import EndpointsTable
from openstack_dashboard.dashboards.project.access_and_security.\
floating_ips.tables import FloatingIPsTable
from openstack_dashboard.dashboards.project.access_and_security.\
@ -109,23 +106,7 @@ class FloatingIPsTab(tabs.TableTab):
return network.floating_ip_supported(request)
class APIAccessTab(tabs.TableTab):
table_classes = (EndpointsTable,)
name = _("API Access")
slug = "api_access_tab"
template_name = "horizon/common/_detail_table.html"
def get_endpoints_data(self):
services = []
for i, service in enumerate(self.request.user.service_catalog):
service['id'] = i
services.append(
keystone.Service(service, self.request.user.services_region))
return services
class AccessAndSecurityTabs(tabs.TabGroup):
slug = "access_security_tabs"
tabs = (SecurityGroupsTab, FloatingIPsTab, APIAccessTab)
tabs = (SecurityGroupsTab, FloatingIPsTab)
sticky = True

View File

@ -1,7 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "User Credentials" %}{% endblock %}
{% block main %}
{% include 'project/access_and_security/api_access/_credentials.html' %}
{% endblock %}

View File

@ -1,7 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Recreate EC2 Credentials" %}{% endblock %}
{% block main %}
{% include 'project/access_and_security/api_access/_recreate_credentials.html' %}
{% endblock %}

View File

@ -25,8 +25,6 @@ import six
from horizon.workflows import views
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security \
import api_access
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -43,9 +41,8 @@ class AccessAndSecurityTests(test.TestCase):
'security_group_list',),
api.nova: ('server_list',),
api.base: ('is_service_enabled',),
quotas: ('tenant_quota_usages',),
api.keystone: ('list_ec2_credentials',)})
def _test_index(self, ec2_enabled=True, instanceless_ips=False):
quotas: ('tenant_quota_usages',)})
def _test_index(self, instanceless_ips=False):
sec_groups = self.security_groups.list()
floating_ips = self.floating_ips.list()
floating_pools = self.pools.list()
@ -71,12 +68,6 @@ class AccessAndSecurityTests(test.TestCase):
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.MultipleTimes().AndReturn(True)
api.base.is_service_enabled(IsA(http.HttpRequest), 'ec2') \
.MultipleTimes().AndReturn(ec2_enabled)
if ec2_enabled:
api.keystone.list_ec2_credentials(IsA(http.HttpRequest),
self.user.id)\
.AndReturn(self.ec2.list())
self.mox.ReplayAll()
@ -99,22 +90,8 @@ class AccessAndSecurityTests(test.TestCase):
all([sec_groups_from_ctx[i].name <= sec_groups_from_ctx[i + 1].name
for i in range(len(sec_groups_from_ctx) - 1)]))
if ec2_enabled:
self.assertTrue(any(map(
lambda x: isinstance(x, api_access.tables.DownloadEC2),
res.context['endpoints_table'].get_table_actions()
)))
else:
self.assertFalse(any(map(
lambda x: isinstance(x, api_access.tables.DownloadEC2),
res.context['endpoints_table'].get_table_actions()
)))
def test_index(self):
self._test_index(ec2_enabled=True)
def test_index_with_ec2_disabled(self):
self._test_index(ec2_enabled=False)
self._test_index()
def test_index_with_instanceless_fips(self):
self._test_index(instanceless_ips=True)
@ -198,9 +175,6 @@ class SecurityGroupTabTests(test.TestCase):
api.base.is_service_enabled(
IsA(http.HttpRequest), 'network').MultipleTimes() \
.AndReturn(True)
api.base.is_service_enabled(
IsA(http.HttpRequest), 'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()
@ -258,9 +232,6 @@ class SecurityGroupTabTests(test.TestCase):
api.base.is_service_enabled(
IsA(http.HttpRequest), 'network').MultipleTimes() \
.AndReturn(network_enabled)
api.base.is_service_enabled(
IsA(http.HttpRequest), 'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()

View File

@ -19,8 +19,6 @@
from django.conf.urls import include
from django.conf.urls import url
from openstack_dashboard.dashboards.project.access_and_security.\
api_access import urls as api_access_urls
from openstack_dashboard.dashboards.project.access_and_security.\
floating_ips import urls as fip_urls
from openstack_dashboard.dashboards.project.access_and_security.\
@ -30,7 +28,6 @@ from openstack_dashboard.dashboards.project.access_and_security import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'api_access/', include(api_access_urls, namespace='api_access')),
url(r'floating_ips/', include(fip_urls, namespace='floating_ips')),
url(r'security_groups/',
include(sec_group_urls, namespace='security_groups')),

View File

@ -0,0 +1,21 @@
# Copyright 2017 Cisco Systems, 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 ApiAccess(horizon.Panel):
name = _("API Access")
slug = 'api_access'

View File

@ -19,8 +19,7 @@ from openstack_auth import utils
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security.api_access \
import forms as project_forms
from openstack_dashboard.dashboards.project.api_access import forms
from openstack_dashboard import policy
@ -38,7 +37,7 @@ class DownloadEC2(tables.LinkAction):
verbose_name = _("Download EC2 Credentials")
verbose_name_plural = _("Download EC2 Credentials")
icon = "download"
url = "horizon:project:access_and_security:api_access:ec2"
url = "horizon:project:api_access:ec2"
policy_rules = (("compute", "compute_extension:certificates"),)
def allowed(self, request, datum=None):
@ -50,7 +49,7 @@ class DownloadOpenRC(tables.LinkAction):
verbose_name = _("Download OpenStack RC File v3")
verbose_name_plural = _("Download OpenStack RC File v3")
icon = "download"
url = "horizon:project:access_and_security:api_access:openrc"
url = "horizon:project:api_access:openrc"
def allowed(self, request, datum=None):
return utils.get_keystone_version() >= 3
@ -61,7 +60,7 @@ class DownloadOpenRCv2(tables.LinkAction):
verbose_name = _("Download OpenStack RC File v2.0")
verbose_name_plural = _("Download OpenStack RC File v2.0")
icon = "download"
url = "horizon:project:access_and_security:api_access:openrcv2"
url = "horizon:project:api_access:openrcv2"
class ViewCredentials(tables.LinkAction):
@ -69,7 +68,7 @@ class ViewCredentials(tables.LinkAction):
verbose_name = _("View Credentials")
classes = ("ajax-modal", )
icon = "eye"
url = "horizon:project:access_and_security:api_access:view_credentials"
url = "horizon:project:api_access:view_credentials"
class RecreateCredentials(tables.LinkAction):
@ -78,7 +77,7 @@ class RecreateCredentials(tables.LinkAction):
classes = ("ajax-modal",)
icon = "refresh"
url = \
"horizon:project:access_and_security:api_access:recreate_credentials"
"horizon:project:api_access:recreate_credentials"
policy_rules = (("compute", "compute_extension:certificates"))
action_type = "danger"
@ -86,7 +85,7 @@ class RecreateCredentials(tables.LinkAction):
try:
target = {"target.credential.user_id": request.user.id}
if (api.base.is_service_enabled(request, 'ec2') and
project_forms.get_ec2_credentials(request) and
forms.get_ec2_credentials(request) and
policy.check((("identity", "identity:ec2_create_credential"),
("identity", "identity:ec2_delete_credential")),
request, target=target)):

View File

@ -65,5 +65,5 @@
{% endblock %}
{% block modal-footer %}
<a href="{% url 'horizon:project:access_and_security:index' %}" class="btn btn-default cancel">{% trans "Close" %}</a>
<a href="{% url 'horizon:project:api_access:index' %}" class="btn btn-default cancel">{% trans "Close" %}</a>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'base.html' %}
{% block main %}
{% include 'project/api_access/_credentials.html' %}
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'base.html' %}
{% block main %}
{% include 'project/api_access/_recreate_credentials.html' %}
{% endblock %}

View File

@ -24,8 +24,8 @@ from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
INDEX_URL = reverse('horizon:project:access_and_security:index')
API_URL = "horizon:project:access_and_security:api_access"
INDEX_URL = reverse('horizon:project:api_access:index')
API_URL = "horizon:project:api_access"
EC2_URL = reverse(API_URL + ":ec2")
OPENRC_URL = reverse(API_URL + ":openrc")
OPENRCV2_URL = reverse(API_URL + ":openrcv2")
@ -60,7 +60,7 @@ class APIAccessTests(test.TestCase):
def test_openrcv2_credentials(self):
res = self.client.get(OPENRCV2_URL)
self.assertEqual(res.status_code, 200)
openrc = 'project/access_and_security/api_access/openrc_v2.sh.template'
openrc = 'project/api_access/openrc_v2.sh.template'
self.assertTemplateUsed(res, openrc)
name = 'export OS_USERNAME="{}"'.format(self.request.user.username)
t_id = 'export OS_TENANT_ID={}'.format(self.request.user.tenant_id)
@ -75,7 +75,7 @@ class APIAccessTests(test.TestCase):
def test_openrc_credentials(self):
res = self.client.get(OPENRC_URL)
self.assertEqual(res.status_code, 200)
openrc = 'project/access_and_security/api_access/openrc.sh.template'
openrc = 'project/api_access/openrc.sh.template'
self.assertTemplateUsed(res, openrc)
name = 'export OS_USERNAME="{}"'.format(self.request.user.username)
p_id = 'export OS_PROJECT_ID={}'.format(self.request.user.tenant_id)
@ -95,7 +95,7 @@ class APIAccessTests(test.TestCase):
res = self.client.get(CREDS_URL)
self.assertEqual(res.status_code, 200)
credentials = 'project/access_and_security/api_access/credentials.html'
credentials = 'project/api_access/credentials.html'
self.assertTemplateUsed(res, credentials)
self.assertEqual(self.user.id, res.context['openrc_creds']['user'].id)
self.assertEqual(certs[0].access,
@ -125,7 +125,7 @@ class APIAccessTests(test.TestCase):
res_get = self.client.get(RECREATE_CREDS_URL)
self.assertEqual(res_get.status_code, 200)
credentials = \
'project/access_and_security/api_access/recreate_credentials.html'
'project/api_access/recreate_credentials.html'
self.assertTemplateUsed(res_get, credentials)
res_post = self.client.post(RECREATE_CREDS_URL)

View File

@ -17,12 +17,10 @@
# under the License.
from django.conf.urls import url
from openstack_dashboard.dashboards.project.access_and_security.\
api_access import views
from openstack_dashboard.dashboards.project.api_access import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^ec2/$', views.download_ec2_bundle, name='ec2'),
url(r'^openrc/$', views.download_rc_file, name='openrc'),
url(r'^openrcv2/$', views.download_rc_file_v2, name='openrcv2'),

View File

@ -28,11 +28,14 @@ from openstack_auth import utils
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon import tables
from horizon import views
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security.api_access \
import forms as project_forms
from openstack_dashboard.dashboards.project.api_access \
import forms as api_access_forms
from openstack_dashboard.dashboards.project.api_access \
import tables as api_access_tables
LOG = logging.getLogger(__name__)
@ -95,7 +98,7 @@ def download_ec2_bundle(request):
redirect=request.build_absolute_uri())
# Create our file bundle
template = 'project/access_and_security/api_access/ec2rc.sh.template'
template = 'project/api_access/ec2rc.sh.template'
try:
temp_zip = tempfile.NamedTemporaryFile(delete=True)
with closing(zipfile.ZipFile(temp_zip.name, mode='w')) as archive:
@ -119,7 +122,7 @@ def download_ec2_bundle(request):
def download_rc_file_v2(request):
template = 'project/access_and_security/api_access/openrc_v2.sh.template'
template = 'project/api_access/openrc_v2.sh.template'
context = _get_openrc_credentials(request)
context['os_identity_api_version'] = 2
context['os_auth_version'] = 2
@ -127,7 +130,7 @@ def download_rc_file_v2(request):
def download_rc_file(request):
template = 'project/access_and_security/api_access/openrc.sh.template'
template = 'project/api_access/openrc.sh.template'
context = _get_openrc_credentials(request)
# make v3 specific changes
@ -159,7 +162,7 @@ def _download_rc_file_for_template(request, context, template):
class CredentialsView(forms.ModalFormMixin, views.HorizonTemplateView):
template_name = 'project/access_and_security/api_access/credentials.html'
template_name = 'project/api_access/credentials.html'
page_title = _("User Credentials Details")
def get_context_data(self, **kwargs):
@ -179,12 +182,27 @@ class CredentialsView(forms.ModalFormMixin, views.HorizonTemplateView):
class RecreateCredentialsView(forms.ModalFormView):
form_class = project_forms.RecreateCredentials
form_class = api_access_forms.RecreateCredentials
form_id = "recreate_credentials"
page_title = _("Recreate EC2 Credentials")
template_name = \
'project/access_and_security/api_access/recreate_credentials.html'
'project/api_access/recreate_credentials.html'
submit_label = _("Recreate EC2 Credentials")
submit_url = reverse_lazy(
"horizon:project:access_and_security:api_access:recreate_credentials")
success_url = reverse_lazy('horizon:project:access_and_security:index')
"horizon:project:api_access:recreate_credentials")
success_url = reverse_lazy('horizon:project:api_access:index')
class IndexView(tables.DataTableView):
table_class = api_access_tables.EndpointsTable
page_title = _("API Access")
def get_data(self):
services = []
for i, service in enumerate(self.request.user.service_catalog):
service['id'] = i
services.append(
api.keystone.Service(service,
self.request.user.services_region))
return services

View File

@ -0,0 +1,6 @@
PANEL_DASHBOARD = 'project'
PANEL_GROUP = 'compute'
PANEL = 'api_access'
ADD_PANEL = \
('openstack_dashboard.dashboards.project.api_access.panel.ApiAccess')

View File

@ -33,7 +33,7 @@ class TemplateRenderTest(test.TestCase):
"auth_url": "http://tests.com",
"tenant_name": "ENG Perf R&D"}
out = loader.render_to_string(
'project/access_and_security/api_access/openrc.sh.template',
'project/api_access/openrc.sh.template',
context,
template.Context(context))
@ -47,7 +47,7 @@ class TemplateRenderTest(test.TestCase):
"auth_url": "http://tests.com",
"tenant_name": 'o"; sudo rm -rf /'}
out = loader.render_to_string(
'project/access_and_security/api_access/openrc.sh.template',
'project/api_access/openrc.sh.template',
context,
template.Context(context))
@ -61,7 +61,7 @@ class TemplateRenderTest(test.TestCase):
"auth_url": "http://tests.com",
"tenant_name": 'o\"; sudo rm -rf /'}
out = loader.render_to_string(
'project/access_and_security/api_access/openrc.sh.template',
'project/api_access/openrc.sh.template',
context,
template.Context(context))
@ -77,7 +77,7 @@ class TemplateRenderTest(test.TestCase):
"tenant_name": "Tenant",
"region": "Colorado"}
out = loader.render_to_string(
'project/access_and_security/api_access/openrc.sh.template',
'project/api_access/openrc.sh.template',
context,
template.Context(context))
@ -90,7 +90,7 @@ class TemplateRenderTest(test.TestCase):
"auth_url": "http://tests.com",
"tenant_name": "Tenant"}
out = loader.render_to_string(
'project/access_and_security/api_access/openrc.sh.template',
'project/api_access/openrc.sh.template',
context,
template.Context(context))

View File

@ -1,5 +1,5 @@
---
features:
- The Access & Security panel's tabs have been moved to their own panels for
clearer navigation and better performance. Key Pairs now resides in the
Compute panel group.
clearer navigation and better performance. API Access and Key Pairs now
reside in the Compute panel group.