diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index edbc491aa0..1d39caccb8 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -840,35 +840,6 @@ def get_default_role(request): return DEFAULT_ROLE -def ec2_manager(request): - client = keystoneclient(request) - if hasattr(client, 'ec2'): - return client.ec2 - - from keystoneclient.v3 import ec2 - return ec2.EC2Manager(client) - - -@profiler.trace -def list_ec2_credentials(request, user_id): - return ec2_manager(request).list(user_id) - - -@profiler.trace -def create_ec2_credentials(request, user_id, tenant_id): - return ec2_manager(request).create(user_id, tenant_id) - - -@profiler.trace -def get_user_ec2_credentials(request, user_id, access_token): - return ec2_manager(request).get(user_id, access_token) - - -@profiler.trace -def delete_user_ec2_credentials(request, user_id, access_token): - return ec2_manager(request).delete(user_id, access_token) - - def keystone_can_edit_domain(): can_edit_domain = setting_utils.get_dict_config( 'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_domain') diff --git a/openstack_dashboard/dashboards/project/api_access/forms.py b/openstack_dashboard/dashboards/project/api_access/forms.py deleted file mode 100644 index 9caf3d9748..0000000000 --- a/openstack_dashboard/dashboards/project/api_access/forms.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2016 NEC Corporation -# -# 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 gettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages - -from openstack_dashboard import api -from openstack_dashboard import policy - - -def get_ec2_credentials(request): - if not policy.check((("identity", "identity:ec2_list_credentials"),), - request): - return None - - project_id = request.user.project_id - all_keys = api.keystone.list_ec2_credentials(request, - request.user.id) - keys = [x for x in all_keys if x.tenant_id == project_id] - if not keys: - return None - return {'ec2_access_key': keys[0].access, - 'ec2_secret_key': keys[0].secret} - - -class RecreateCredentials(forms.SelfHandlingForm): - - def handle(self, request, context): - try: - credential = get_ec2_credentials(request) - if credential: - api.keystone.delete_user_ec2_credentials( - request, - request.user.id, - credential['ec2_access_key']) - except Exception: - exceptions.handle( - request, _('Unable to recreate ec2 credentials. ' - 'Failed to delete ec2 credentials.')) - return False - - try: - api.keystone.create_ec2_credentials( - request, - request.user.id, - request.user.project_id) - message = _('Successfully recreated ec2 credentials.') - messages.success(request, message) - return True - except Exception: - exceptions.handle( - request, _('Unable to recreate ec2 credentials. ' - 'Failed to create ec2 credentials.')) - return False diff --git a/openstack_dashboard/dashboards/project/api_access/tables.py b/openstack_dashboard/dashboards/project/api_access/tables.py index d826f9a061..b449d7d8e8 100644 --- a/openstack_dashboard/dashboards/project/api_access/tables.py +++ b/openstack_dashboard/dashboards/project/api_access/tables.py @@ -17,31 +17,17 @@ from django.template.defaultfilters import title from django.utils.translation import gettext_lazy as _ from horizon import tables -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.api_access import forms -from openstack_dashboard import policy def pretty_service_names(name): name = name.replace('-', ' ') - if name in ['ec2', 's3']: + if name in ('s3',): name = name.upper() else: name = title(name) return name -class DownloadEC2(tables.LinkAction): - name = "download_ec2" - verbose_name = _("EC2 Credentials") - verbose_name_plural = _("EC2 Credentials") - icon = "download" - url = "horizon:project:api_access:ec2" - - def allowed(self, request, datum=None): - return api.base.is_service_enabled(request, 'ec2') - - class DownloadCloudsYaml(tables.LinkAction): name = "download_clouds_yaml" verbose_name = _("OpenStack clouds.yaml File") @@ -72,29 +58,6 @@ class ViewCredentials(tables.LinkAction): url = "horizon:project:api_access:view_credentials" -class RecreateCredentials(tables.LinkAction): - name = "recreate_credentials" - verbose_name = _("Recreate EC2 Credentials") - classes = ("ajax-modal",) - icon = "refresh" - url = "horizon:project:api_access:recreate_credentials" - policy_rules = (("compute", "os_compute_api:certificates:create")) - action_type = "danger" - - def allowed(self, request, datum=None): - try: - target = {"target.credential.user_id": request.user.id} - if (api.base.is_service_enabled(request, 'ec2') and - forms.get_ec2_credentials(request) and - policy.check((("identity", "identity:ec2_create_credential"), - ("identity", "identity:ec2_delete_credential")), - request, target=target)): - return True - except Exception: - pass - return False - - class EndpointsTable(tables.DataTable): api_name = tables.Column('type', verbose_name=_("Service"), @@ -106,8 +69,7 @@ class EndpointsTable(tables.DataTable): name = "endpoints" verbose_name = _("API Endpoints") multi_select = False - table_actions = (ViewCredentials, RecreateCredentials) + table_actions = (ViewCredentials,) table_actions_menu = (DownloadCloudsYaml, - DownloadOpenRC, - DownloadEC2) + DownloadOpenRC) table_actions_menu_label = _('Download OpenStack RC File') diff --git a/openstack_dashboard/dashboards/project/api_access/templates/api_access/_credentials.html b/openstack_dashboard/dashboards/project/api_access/templates/api_access/_credentials.html index f755d2c437..c610cc1e09 100644 --- a/openstack_dashboard/dashboards/project/api_access/templates/api_access/_credentials.html +++ b/openstack_dashboard/dashboards/project/api_access/templates/api_access/_credentials.html @@ -4,57 +4,31 @@ {% block modal-body %}
{% if openrc_creds %} -
-
- - -
-
- - -
- {% if "user_domain_name" in openrc_creds %} -
- - -
- {% endif %} -
- - -
-
- - -
-
- - -
+
+ +
- {% endif %} - {% if ec2_creds %} -
-
- - -
-
- - -
- {% if ec2_creds.ec2_access_key %} -
- - -
- {% endif %} - {% if ec2_creds.ec2_secret_key %} -
- - -
- {% endif %} +
+ + +
+ {% if "user_domain_name" in openrc_creds %} +
+ + +
+ {% endif %} +
+ + +
+
+ + +
+
+ +
{% endif %} diff --git a/openstack_dashboard/dashboards/project/api_access/templates/api_access/ec2rc.sh.template b/openstack_dashboard/dashboards/project/api_access/templates/api_access/ec2rc.sh.template deleted file mode 100644 index 0b6f7e2730..0000000000 --- a/openstack_dashboard/dashboards/project/api_access/templates/api_access/ec2rc.sh.template +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -NOVARC=$(readlink -f "${BASH_SOURCE:-${0}}" 2>/dev/null) || NOVARC=$(python -c 'import os,sys; print os.path.abspath(os.path.realpath(sys.argv[1]))' "${BASH_SOURCE:-${0}}") -NOVA_KEY_DIR=${NOVARC%/*} -export EC2_ACCESS_KEY={{ ec2_access_key }} -export EC2_SECRET_KEY={{ ec2_secret_key }} -export EC2_URL={{ ec2_endpoint }} -export EC2_USER_ID=42 # nova does not use user id, but bundling requires it -export EC2_PRIVATE_KEY=${NOVA_KEY_DIR}/pk.pem -export EC2_CERT=${NOVA_KEY_DIR}/cert.pem -export NOVA_CERT=${NOVA_KEY_DIR}/cacert.pem -export EUCALYPTUS_CERT=${NOVA_CERT} # euca-bundle-image seems to require this set -{% if s3_endpoint %}export S3_URL={{ s3_endpoint }}{% endif %} -alias ec2-bundle-image="ec2-bundle-image --cert ${EC2_CERT} --privatekey ${EC2_PRIVATE_KEY} --user 42 --ec2cert ${NOVA_CERT}" -alias ec2-upload-bundle="ec2-upload-bundle -a ${EC2_ACCESS_KEY} -s ${EC2_SECRET_KEY} --url ${S3_URL} --ec2cert ${NOVA_CERT}" diff --git a/openstack_dashboard/dashboards/project/api_access/templates/api_access/recreate_credentials.html b/openstack_dashboard/dashboards/project/api_access/templates/api_access/recreate_credentials.html deleted file mode 100644 index 24c777f08d..0000000000 --- a/openstack_dashboard/dashboards/project/api_access/templates/api_access/recreate_credentials.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'base.html' %} - -{% block main %} - {% include 'project/api_access/_recreate_credentials.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/api_access/tests.py b/openstack_dashboard/dashboards/project/api_access/tests.py index 66d5709997..9b628205a6 100644 --- a/openstack_dashboard/dashboards/project/api_access/tests.py +++ b/openstack_dashboard/dashboards/project/api_access/tests.py @@ -19,34 +19,16 @@ from django.template import loader from django.test.utils import override_settings from django.urls import reverse -from openstack_dashboard import api from openstack_dashboard.test import helpers as test 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") CREDS_URL = reverse(API_URL + ":view_credentials") -RECREATE_CREDS_URL = reverse(API_URL + ":recreate_credentials") class APIAccessTests(test.TestCase): - @test.create_mocks({api.keystone: ('create_ec2_credentials', - 'list_ec2_credentials')}) - def test_ec2_download_view(self): - creds = self.ec2.first() - self.mock_list_ec2_credentials.return_value = [] - self.mock_create_ec2_credentials.return_value = creds - - res = self.client.get(EC2_URL) - self.assertEqual(res.status_code, 200) - self.assertEqual(res['content-type'], 'application/zip') - - self.mock_list_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id) - self.mock_create_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id, self.tenant.id) @override_settings(OPENSTACK_API_VERSIONS={"identity": 3}) def test_openrc_credentials(self): @@ -62,59 +44,6 @@ class APIAccessTests(test.TestCase): self.assertIn(p_id.encode('utf-8'), res.content) self.assertIn(domain.encode('utf-8'), res.content) - @test.create_mocks({api.keystone: ('list_ec2_credentials',)}) - def test_credential_api(self): - certs = self.ec2.list() - self.mock_list_ec2_credentials.return_value = certs - - res = self.client.get(CREDS_URL) - - self.assertEqual(res.status_code, 200) - 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, - res.context['ec2_creds']['ec2_access_key']) - self.mock_list_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id) - - @test.create_mocks({api.keystone: ('create_ec2_credentials', - 'list_ec2_credentials', - 'delete_user_ec2_credentials')}) - def _test_recreate_user_credentials(self, exists_credentials=True): - old_creds = self.ec2.list() if exists_credentials else [] - new_creds = self.ec2.first() - self.mock_list_ec2_credentials.return_value = old_creds - if exists_credentials: - self.mock_delete_user_ec2_credentials.return_value = [] - self.mock_create_ec2_credentials.return_value = new_creds - - res_get = self.client.get(RECREATE_CREDS_URL) - self.assertEqual(res_get.status_code, 200) - credentials = \ - 'project/api_access/recreate_credentials.html' - self.assertTemplateUsed(res_get, credentials) - - res_post = self.client.post(RECREATE_CREDS_URL) - self.assertNoFormErrors(res_post) - self.assertRedirectsNoFollow(res_post, INDEX_URL) - - self.mock_list_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id) - if exists_credentials: - self.mock_delete_user_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id, old_creds[0].access) - else: - self.mock_delete_user_ec2_credentials.assert_not_called() - self.mock_create_ec2_credentials.assert_called_once_with( - test.IsHttpRequest(), self.user.id, self.tenant.id) - - def test_recreate_user_credentials(self): - self._test_recreate_user_credentials() - - def test_recreate_user_credentials_with_no_existing_creds(self): - self._test_recreate_user_credentials(exists_credentials=False) - class ASCIITenantNameRCTests(test.TestCase): TENANT_NAME = 'tenant' diff --git a/openstack_dashboard/dashboards/project/api_access/urls.py b/openstack_dashboard/dashboards/project/api_access/urls.py index e07fef5063..dd6152eea1 100644 --- a/openstack_dashboard/dashboards/project/api_access/urls.py +++ b/openstack_dashboard/dashboards/project/api_access/urls.py @@ -22,13 +22,9 @@ from openstack_dashboard.dashboards.project.api_access import views urlpatterns = [ re_path(r'^$', views.IndexView.as_view(), name='index'), - re_path(r'^ec2/$', views.download_ec2_bundle, name='ec2'), re_path(r'^clouds.yaml/$', views.download_clouds_yaml_file, name='clouds.yaml'), re_path(r'^openrc/$', views.download_rc_file, name='openrc'), re_path(r'^view_credentials/$', views.CredentialsView.as_view(), name='view_credentials'), - re_path(r'^recreate_ec2_credentials/$', - views.RecreateCredentialsView.as_view(), - name='recreate_credentials'), ] diff --git a/openstack_dashboard/dashboards/project/api_access/views.py b/openstack_dashboard/dashboards/project/api_access/views.py index 6c671280fd..530579039e 100644 --- a/openstack_dashboard/dashboards/project/api_access/views.py +++ b/openstack_dashboard/dashboards/project/api_access/views.py @@ -12,16 +12,12 @@ # License for the specific language governing permissions and limitations # under the License. -from contextlib import closing import logging -import tempfile -import zipfile from django.conf import settings from django import http from django import shortcuts from django.template.loader import render_to_string -from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from horizon import exceptions @@ -31,44 +27,12 @@ from horizon import tables from horizon import views from openstack_dashboard import api -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__) -def _get_ec2_credentials(request): - tenant_id = request.user.tenant_id - all_keys = api.keystone.list_ec2_credentials(request, - request.user.id) - - key = next((x for x in all_keys if x.tenant_id == tenant_id), None) - if not key: - key = api.keystone.create_ec2_credentials(request, - request.user.id, - tenant_id) - try: - s3_endpoint = api.base.url_for(request, - 's3', - endpoint_type='publicURL') - except exceptions.ServiceCatalogException: - s3_endpoint = None - - try: - ec2_endpoint = api.base.url_for(request, - 'ec2', - endpoint_type='publicURL') - except exceptions.ServiceCatalogException: - ec2_endpoint = None - - return {'ec2_access_key': key.access, - 'ec2_secret_key': key.secret, - 'ec2_endpoint': ec2_endpoint, - 's3_endpoint': s3_endpoint} - - def _get_openrc_credentials(request): keystone_url = api.base.url_for(request, 'identity', @@ -85,40 +49,6 @@ def _get_openrc_credentials(request): } -# TODO(stephenfin): Migrate to CBV -def download_ec2_bundle(request): - tenant_name = request.user.tenant_name - - # Gather or create our EC2 credentials - try: - context = _get_ec2_credentials(request) - except Exception: - exceptions.handle(request, - _('Unable to fetch EC2 credentials.'), - redirect=request.build_absolute_uri()) - - # Create our file bundle - template = 'project/api_access/ec2rc.sh.template' - try: - # pylint: disable-next=consider-using-with - temp_zip = tempfile.NamedTemporaryFile(delete=True) - with closing(zipfile.ZipFile(temp_zip.name, mode='w')) as archive: - archive.writestr('ec2rc.sh', render_to_string(template, context)) - except Exception: - exceptions.handle(request, - _('Error writing zipfile: %(exc)s'), - redirect=request.build_absolute_uri()) - - # Send it back - response = http.HttpResponse(content_type='application/zip') - response.write(temp_zip.read()) - response['Content-Disposition'] = ('attachment; ' - 'filename="%s-x509.zip"' - % tenant_name) - response['Content-Length'] = temp_zip.tell() - return response - - # TODO(stephenfin): Migrate to CBV def download_rc_file(request): template = settings.OPENRC_CUSTOM_TEMPLATE @@ -186,27 +116,9 @@ class CredentialsView(forms.ModalFormMixin, views.HorizonTemplateView): except Exception: exceptions.handle(self.request, _('Unable to get openrc credentials')) - if api.base.is_service_enabled(self.request, 'ec2'): - try: - context['ec2_creds'] = _get_ec2_credentials(self.request) - except Exception: - exceptions.handle(self.request, - _('Unable to get EC2 credentials')) return context -class RecreateCredentialsView(forms.ModalFormView): - form_class = api_access_forms.RecreateCredentials - form_id = "recreate_credentials" - page_title = _("Recreate EC2 Credentials") - template_name = \ - 'project/api_access/recreate_credentials.html' - submit_label = _("Recreate EC2 Credentials") - submit_url = reverse_lazy( - "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") diff --git a/openstack_dashboard/test/test_data/keystone_data.py b/openstack_dashboard/test/test_data/keystone_data.py index 72407bfd6d..ae1510b987 100644 --- a/openstack_dashboard/test/test_data/keystone_data.py +++ b/openstack_dashboard/test/test_data/keystone_data.py @@ -19,7 +19,6 @@ from django.conf import settings from django.utils import datetime_safe from keystoneclient import access -from keystoneclient.v2_0 import ec2 from keystoneclient.v2_0 import roles from keystoneclient.v2_0 import tenants from keystoneclient.v2_0 import users @@ -145,21 +144,7 @@ SERVICE_CATALOG = [ {"region": "RegionOne", "interface": "public", "url": "http://public.neutron.example.com:9696/"} - ]}, - {"type": "ec2", - "name": "EC2 Service", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "interface": "admin", - "url": "http://admin.nova.example.com:8773/services/Admin"}, - {"region": "RegionOne", - "interface": "public", - "url": "http://public.nova.example.com:8773/services/Cloud"}, - {"region": "RegionOne", - "interface": "internal", - "url": "http://int.nova.example.com:8773/services/Cloud"} - ]}, + ]} ] @@ -175,7 +160,6 @@ def data(TEST): TEST.tenants = utils.TestDataContainer() TEST.role_assignments = utils.TestDataContainer() TEST.roles = utils.TestDataContainer() - TEST.ec2 = utils.TestDataContainer() TEST.identity_providers = utils.TestDataContainer() TEST.idp_mappings = utils.TestDataContainer() @@ -439,11 +423,6 @@ def data(TEST): TEST.tokens.scoped_token = scoped_token TEST.tokens.unscoped_token = unscoped_token - access_secret = ec2.EC2(ec2.CredentialsManager, {"access": "access", - "secret": "secret", - "tenant_id": tenant.id}) - TEST.ec2.add(access_secret) - idp_dict_1 = {'id': 'idp_1', 'description': 'identity provider 1', 'enabled': True, diff --git a/releasenotes/notes/remove-ec2-creds-7869cba1e7e13af1.yaml b/releasenotes/notes/remove-ec2-creds-7869cba1e7e13af1.yaml new file mode 100644 index 0000000000..1a4d574d75 --- /dev/null +++ b/releasenotes/notes/remove-ec2-creds-7869cba1e7e13af1.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - | + The following features are no longer supported. These have been disabled + unless EC2-API service is deployed, but EC2-API project was already + retired. + + - Download EC2 credentials + - Recreate EC2 credentials