Browse Source

Merge "Prevent duplicated backend names"

tags/2.0.0
Zuul 4 weeks ago
committed by Gerrit Code Review
parent
commit
4347547a0d
3 changed files with 72 additions and 1 deletions
  1. +21
    -1
      cinderlib/cinderlib.py
  2. +45
    -0
      cinderlib/tests/unit/test_cinderlib.py
  3. +6
    -0
      releasenotes/notes/backend-same-name-86a06844b57600a0.yaml

+ 21
- 1
cinderlib/cinderlib.py View File

@@ -67,11 +67,30 @@ class Backend(object):
# With this dictionary the DB class can get the necessary data
_volumes_inflight = {}

def __new__(cls, volume_backend_name, **driver_cfg):
# Prevent redefinition of an already initialized backend on the same
# persistence storage with a different configuration.
backend = Backend.backends.get(volume_backend_name)
if backend:
# If we are instantiating the same backend return the one we have
# saved (singleton pattern).
if driver_cfg == backend._original_driver_cfg:
return backend
raise ValueError('Backend named %s already exists with a different'
' configuration' % volume_backend_name)

return super(Backend, cls).__new__(cls)

def __init__(self, volume_backend_name, **driver_cfg):
if not self.global_initialization:
self.global_setup()
# Instance already initialized
if volume_backend_name in Backend.backends:
return
# Save the original config before we add the backend name and template
# the values.
self._original_driver_cfg = driver_cfg.copy()
driver_cfg['volume_backend_name'] = volume_backend_name
Backend.backends[volume_backend_name] = self

conf = self._get_backend_config(driver_cfg)
self._apply_backend_workarounds(conf)
@@ -99,6 +118,7 @@ class Backend(object):
self._stats = self._transform_legacy_stats(stats)

self._pool_names = tuple(pool['pool_name'] for pool in stats['pools'])
Backend.backends[volume_backend_name] = self

@property
def pool_names(self):


+ 45
- 0
cinderlib/tests/unit/test_cinderlib.py View File

@@ -101,6 +101,51 @@ class TestCinderlib(base.BaseTest):
self.assertEqual(('default',), backend.pool_names)
mock_workarounds.assert_called_once_with(mock_config.return_value)

@mock.patch.object(objects.Backend, 'global_initialization', True)
@mock.patch.object(objects.Backend, '_apply_backend_workarounds')
@mock.patch('oslo_utils.importutils.import_object')
@mock.patch.object(objects.Backend, '_get_backend_config')
def test_init_call_twice(self, mock_config, mock_import, mock_workarounds):
cinderlib.Backend.global_initialization = False
driver_cfg = {'k': 'v', 'k2': 'v2', 'volume_backend_name': 'Test'}
driver = mock_import.return_value
driver.capabilities = {'pools': [{'pool_name': 'default'}]}

backend = objects.Backend(**driver_cfg)
self.assertEqual(1, mock_config.call_count)
self.assertEqual(1, mock_import.call_count)
self.assertEqual(1, mock_workarounds.call_count)

# When initiallizing a Backend with the same configuration the Backend
# class must behave as a singleton and we won't initialize it again
backend_second = objects.Backend(**driver_cfg)
self.assertIs(backend, backend_second)
self.assertEqual(1, mock_config.call_count)
self.assertEqual(1, mock_import.call_count)
self.assertEqual(1, mock_workarounds.call_count)

@mock.patch.object(objects.Backend, 'global_initialization', True)
@mock.patch.object(objects.Backend, '_apply_backend_workarounds')
@mock.patch('oslo_utils.importutils.import_object')
@mock.patch.object(objects.Backend, '_get_backend_config')
def test_init_call_twice_different_config(self, mock_config, mock_import,
mock_workarounds):
cinderlib.Backend.global_initialization = False
driver_cfg = {'k': 'v', 'k2': 'v2', 'volume_backend_name': 'Test'}
driver = mock_import.return_value
driver.capabilities = {'pools': [{'pool_name': 'default'}]}

objects.Backend(**driver_cfg)
self.assertEqual(1, mock_config.call_count)
self.assertEqual(1, mock_import.call_count)
self.assertEqual(1, mock_workarounds.call_count)

# It should fail if we reuse the backend name but change the config
self.assertRaises(ValueError, objects.Backend, k3='v3', **driver_cfg)
self.assertEqual(1, mock_config.call_count)
self.assertEqual(1, mock_import.call_count)
self.assertEqual(1, mock_workarounds.call_count)

@mock.patch('cinderlib.Backend._validate_and_set_options')
@mock.patch.object(cfg, 'CONF')
def test__set_cinder_config(self, conf_mock, validate_mock):


+ 6
- 0
releasenotes/notes/backend-same-name-86a06844b57600a0.yaml View File

@@ -0,0 +1,6 @@
---
fixes:
- |
Prevent the creation of multiple backends with the same name during the
same code run.
(Bug #1886164).

Loading…
Cancel
Save