diff --git a/openstack/service_description.py b/openstack/service_description.py index d319b686b..f154e92f8 100644 --- a/openstack/service_description.py +++ b/openstack/service_description.py @@ -218,4 +218,13 @@ class ServiceDescription(object): raise AttributeError('Service Descriptors cannot be set') def __delete__(self, instance): - raise AttributeError('Service Descriptors cannot be deleted') + # NOTE(gtema) Some clouds are not very fast (or interested at all) + # in bringing their changes upstream. If there are incompatible changes + # downstream we need to allow overriding default implementation by + # deleting service_type attribute of the connection and then + # "add_service" with new implementation. + # This is implemented explicitely not very comfortable to use + # to show how bad it is not to contribute changes back + for service_type in self.all_types: + if service_type in instance._proxies: + del instance._proxies[service_type] diff --git a/openstack/tests/unit/test_connection.py b/openstack/tests/unit/test_connection.py index ce2320cc6..ef4117f96 100644 --- a/openstack/tests/unit/test_connection.py +++ b/openstack/tests/unit/test_connection.py @@ -308,3 +308,29 @@ class TestNewService(base.TestCase): 'openstack.tests.unit.fake.v2._proxy', conn.fake.__class__.__module__) self.assertFalse(conn.fake.dummy()) + + def test_replace_system_service(self): + self.use_keystone_v3(catalog='catalog-v3-fake-v2.json') + conn = self.cloud + + # delete native dns service + delattr(conn, 'dns') + + self.register_uris([ + dict(method='GET', + uri='https://fake.example.com', + status_code=404), + dict(method='GET', + uri='https://fake.example.com/v2/', + status_code=404), + dict(method='GET', + uri=self.get_mock_url('fake'), + status_code=404), + ]) + + # add fake service with alias 'DNS' + service = fake_service.FakeService('fake', aliases=['dns']) + conn.add_service(service) + + # ensure dns service responds as we expect from replacement + self.assertFalse(conn.dns.dummy())