From 46c7fa492ffbef35f7292775eaa50fc62f290e54 Mon Sep 17 00:00:00 2001 From: Radoslav Gerganov Date: Tue, 18 Jul 2017 11:18:42 +0300 Subject: [PATCH] VMware: Handle concurrent registrations of the VC extension During initialization, the Nova compute driver checks whether a vCenter extension with key 'org.openstack.compute' exists and if not, it registers one. This is a race condition. If multiple services try to register the same extension, only one of them will succeed. The fix is to catch InvalidArgument fault from vSphere API and ignore the exception. Change-Id: I92c24709a2f55b601c31a31b9e748f19e7e31984 Closes-Bug: #1704952 --- .../unit/virt/vmwareapi/test_driver_api.py | 12 +++++++++++ nova/virt/vmwareapi/driver.py | 21 ++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/nova/tests/unit/virt/vmwareapi/test_driver_api.py b/nova/tests/unit/virt/vmwareapi/test_driver_api.py index 379e73aeeda2..b3711d62dbe2 100644 --- a/nova/tests/unit/virt/vmwareapi/test_driver_api.py +++ b/nova/tests/unit/virt/vmwareapi/test_driver_api.py @@ -2055,6 +2055,18 @@ class VMwareAPIVMTestCase(test.NoDBTestCase, 'find_extension', constants.EXTENSION_KEY) + def test_register_extension_concurrent(self): + def fake_call_method(module, method, *args, **kwargs): + if method == "find_extension": + return None + elif method == "register_extension": + raise vexc.VimFaultException(['InvalidArgument'], 'error') + else: + raise Exception() + with (mock.patch.object( + self.conn._session, '_call_method', fake_call_method)): + self.conn._register_openstack_extension() + def test_list_instances(self): instances = self.conn.list_instances() self.assertEqual(0, len(instances)) diff --git a/nova/virt/vmwareapi/driver.py b/nova/virt/vmwareapi/driver.py index 79913a80a4a2..823147c36790 100644 --- a/nova/virt/vmwareapi/driver.py +++ b/nova/virt/vmwareapi/driver.py @@ -183,16 +183,23 @@ class VMwareVCDriver(driver.ComputeDriver): def _register_openstack_extension(self): # Register an 'OpenStack' extension in vCenter - LOG.debug('Registering extension %s with vCenter', - constants.EXTENSION_KEY) os_extension = self._session._call_method(vim_util, 'find_extension', constants.EXTENSION_KEY) if os_extension is None: - LOG.debug('Extension does not exist. Registering type %s.', - constants.EXTENSION_TYPE_INSTANCE) - self._session._call_method(vim_util, 'register_extension', - constants.EXTENSION_KEY, - constants.EXTENSION_TYPE_INSTANCE) + try: + self._session._call_method(vim_util, 'register_extension', + constants.EXTENSION_KEY, + constants.EXTENSION_TYPE_INSTANCE) + LOG.info('Registered extension %s with vCenter', + constants.EXTENSION_KEY) + except vexc.VimFaultException as e: + with excutils.save_and_reraise_exception() as ctx: + if 'InvalidArgument' in e.fault_list: + LOG.debug('Extension %s already exists.', + constants.EXTENSION_KEY) + ctx.reraise = False + else: + LOG.debug('Extension %s already exists.', constants.EXTENSION_KEY) def cleanup(self, context, instance, network_info, block_device_info=None, destroy_disks=True, migrate_data=None, destroy_vifs=True):