From 3326bb7706e45de2c00937a0e478012faf555ca3 Mon Sep 17 00:00:00 2001 From: SamYaple Date: Sun, 6 Mar 2016 16:38:09 +0000 Subject: [PATCH] Add update_endpoint() v3 allows us to update the endpoints, we should do that. The other endpoint calls have been validated against v3 api to do what we want them to do. All comments regarding implementing v3 keystone have been removed. Change-Id: Icae8a02815b1416a60bc8c6d57ee892fbfd7ccc4 --- .../update_endpoint-f87c1f42d0c0d1ef.yaml | 8 +++++ shade/_tasks.py | 5 +++ shade/operatorcloud.py | 26 ++++++++++++-- shade/tests/functional/test_endpoints.py | 34 ++++++++++++++++++ shade/tests/unit/test_endpoints.py | 36 +++++++++++++++++++ 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/update_endpoint-f87c1f42d0c0d1ef.yaml diff --git a/releasenotes/notes/update_endpoint-f87c1f42d0c0d1ef.yaml b/releasenotes/notes/update_endpoint-f87c1f42d0c0d1ef.yaml new file mode 100644 index 000000000..a7b6a458b --- /dev/null +++ b/releasenotes/notes/update_endpoint-f87c1f42d0c0d1ef.yaml @@ -0,0 +1,8 @@ +--- +features: + - Added update_endpoint as a new function that allows + the user to update a created endpoint with new values + rather than deleting and recreating that endpoint. + This feature only works with keystone v3, with v2 it + will raise an exception stating the feature is not + available. diff --git a/shade/_tasks.py b/shade/_tasks.py index 47ffd9538..238eafe20 100644 --- a/shade/_tasks.py +++ b/shade/_tasks.py @@ -724,6 +724,11 @@ class EndpointCreate(task_manager.Task): return client.keystone_client.endpoints.create(**self.args) +class EndpointUpdate(task_manager.Task): + def main(self, client): + return client.keystone_client.endpoints.update(**self.args) + + class EndpointList(task_manager.Task): def main(self, client): return client.keystone_client.endpoints.list() diff --git a/shade/operatorcloud.py b/shade/operatorcloud.py index 77c63c38a..c93cabab8 100644 --- a/shade/operatorcloud.py +++ b/shade/operatorcloud.py @@ -980,6 +980,26 @@ class OperatorCloud(openstackcloud.OpenStackCloud): endpoints.append(endpoint) return endpoints + @_utils.valid_kwargs('enabled', 'service_name_or_id', 'url', 'interface', + 'region') + def update_endpoint(self, endpoint_id, **kwargs): + # NOTE(SamYaple): Endpoint updates are only available on v3 api + if self.cloud_config.get_api_version('identity').startswith('2'): + raise OpenStackCloudUnavailableFeature( + 'Unavailable Feature: Endpoint update' + ) + + service_name_or_id = kwargs.pop('service_name_or_id', None) + if service_name_or_id is not None: + kwargs['service'] = service_name_or_id + + with _utils.shade_exceptions( + "Failed to update endpoint {}".format(endpoint_id) + ): + return self.manager.submitTask(_tasks.EndpointUpdate( + endpoint=endpoint_id, **kwargs + )) + def list_endpoints(self): """List Keystone endpoints. @@ -988,7 +1008,10 @@ class OperatorCloud(openstackcloud.OpenStackCloud): :raises: ``OpenStackCloudException``: if something goes wrong during the openstack API call. """ - # ToDo: support v3 api (dguerri) + # NOTE(SamYaple): With keystone v3 we can filter directly via the + # the keystone api, but since the return of all the endpoints even in + # large environments is small, we can continue to filter in shade just + # like the v2 api. with _utils.shade_exceptions("Failed to list endpoints"): endpoints = self.manager.submitTask(_tasks.EndpointList()) @@ -1042,7 +1065,6 @@ class OperatorCloud(openstackcloud.OpenStackCloud): :raises: ``OpenStackCloudException`` if something goes wrong during the openstack API call. """ - # ToDo: support v3 api (dguerri) endpoint = self.get_endpoint(id=id) if endpoint is None: self.log.debug("Endpoint %s not found for deleting" % id) diff --git a/shade/tests/functional/test_endpoints.py b/shade/tests/functional/test_endpoints.py index ca79f855f..e7346fe64 100644 --- a/shade/tests/functional/test_endpoints.py +++ b/shade/tests/functional/test_endpoints.py @@ -25,6 +25,7 @@ import string import random from shade.exc import OpenStackCloudException +from shade.exc import OpenStackCloudUnavailableFeature from shade.tests.functional import base @@ -101,6 +102,39 @@ class TestEndpoints(base.BaseFunctionalTestCase): self.assertNotEqual([], endpoints) self.assertIsNotNone(endpoints[0].get('id')) + def test_update_endpoint(self): + if self.operator_cloud.cloud_config.get_api_version( + 'identity').startswith('2'): + # NOTE(SamYaple): Update endpoint only works with v3 api + self.assertRaises(OpenStackCloudUnavailableFeature, + self.operator_cloud.update_endpoint, + 'endpoint_id1') + else: + service = self.operator_cloud.create_service( + name='service1', type='test_type') + endpoint = self.operator_cloud.create_endpoint( + service_name_or_id=service['id'], + url='http://admin.url/', + interface='admin', + region='orig_region', + enabled=False)[0] + + new_service = self.operator_cloud.create_service( + name='service2', type='test_type') + new_endpoint = self.operator_cloud.update_endpoint( + endpoint.id, + service_name_or_id=new_service.id, + url='http://public.url/', + interface='public', + region='update_region', + enabled=True) + + self.assertEqual(new_endpoint.url, 'http://public.url/') + self.assertEqual(new_endpoint.interface, 'public') + self.assertEqual(new_endpoint.region, 'update_region') + self.assertEqual(new_endpoint.service_id, new_service.id) + self.assertTrue(new_endpoint.enabled) + def test_list_endpoints(self): service_name = self.new_item_name + '_list' diff --git a/shade/tests/unit/test_endpoints.py b/shade/tests/unit/test_endpoints.py index a0c596903..1d85eebfa 100644 --- a/shade/tests/unit/test_endpoints.py +++ b/shade/tests/unit/test_endpoints.py @@ -23,6 +23,7 @@ from mock import patch import os_client_config from shade import OperatorCloud from shade.exc import OpenStackCloudException +from shade.exc import OpenStackCloudUnavailableFeature from shade.tests.fakes import FakeEndpoint from shade.tests.fakes import FakeEndpointv3 from shade.tests.unit import base @@ -170,6 +171,41 @@ class TestCloudEndpoints(base.TestCase): for k, v in self.mock_endpoints_v3[count].items(): self.assertEquals(v, endpoints_2on3[count].get(k)) + @patch.object(os_client_config.cloud_config.CloudConfig, 'get_api_version') + def test_update_endpoint_v2(self, mock_api_version): + mock_api_version.return_value = '2.0' + # NOTE(SamYaple): Update endpoint only works with v3 api + self.assertRaises(OpenStackCloudUnavailableFeature, + self.client.update_endpoint, 'endpoint_id') + + @patch.object(OperatorCloud, 'keystone_client') + @patch.object(os_client_config.cloud_config.CloudConfig, 'get_api_version') + def test_update_endpoint_v3(self, mock_api_version, mock_keystone_client): + mock_api_version.return_value = '3' + mock_keystone_client.endpoints.update.return_value = \ + self.mock_ks_endpoints_v3[0] + + endpoint = self.client.update_endpoint( + 'id1', + service_name_or_id='service_id1', + region='mock_region', + url='mock_url', + interface='mock_interface', + enabled=False + ) + mock_keystone_client.endpoints.update.assert_called_with( + endpoint='id1', + service='service_id1', + region='mock_region', + url='mock_url', + interface='mock_interface', + enabled=False + ) + + # test keys and values are correct + for k, v in self.mock_endpoints_v3[0].items(): + self.assertEquals(v, endpoint.get(k)) + @patch.object(OperatorCloud, 'keystone_client') def test_list_endpoints(self, mock_keystone_client): mock_keystone_client.endpoints.list.return_value = \